mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-27 20:49:03 +08:00
feat: 完善 PostgreSQL 功能 (#3499)
This commit is contained in:
parent
4d19e3904b
commit
9561336934
@ -94,50 +94,6 @@ func (b *BaseApi) ChangePostgresqlPassword(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Change postgresql access
|
||||
// @Description 修改 postgresql 访问权限
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangeDBInfo true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/change/access [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_postgresqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"}
|
||||
func (b *BaseApi) ChangePostgresqlAccess(c *gin.Context) {
|
||||
var req dto.ChangeDBInfo
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := postgresqlService.ChangeAccess(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Update postgresql variables
|
||||
// @Description postgresql 性能调优
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlVariablesUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/variables/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"调整 postgresql 数据库性能参数","formatEN":"adjust postgresql database performance parameters"}
|
||||
func (b *BaseApi) UpdatePostgresqlVariables(c *gin.Context) {
|
||||
//var req dto.PostgresqlVariablesUpdate
|
||||
//if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//if err := postgresqlService.UpdateVariables(req); err != nil {
|
||||
// helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
// return
|
||||
//}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Update postgresql conf by upload file
|
||||
// @Description 上传替换 postgresql 配置文件
|
||||
@ -213,15 +169,17 @@ func (b *BaseApi) ListPostgresqlDBName(c *gin.Context) {
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/load [post]
|
||||
func (b *BaseApi) LoadPostgresqlDBFromRemote(c *gin.Context) {
|
||||
//var req dto.PostgresqlLoadDB
|
||||
//if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//if err := postgresqlService.LoadFromRemote(req); err != nil {
|
||||
// helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
// return
|
||||
//}
|
||||
var req dto.PostgresqlLoadDB
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := postgresqlService.LoadFromRemote(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@ -294,28 +252,3 @@ func (b *BaseApi) LoadPostgresqlBaseinfo(c *gin.Context) {
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Load postgresql status info
|
||||
// @Description 获取 postgresql 状态信息
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200 {object} dto.PostgresqlStatus
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/status [post]
|
||||
func (b *BaseApi) LoadPostgresqlStatus(c *gin.Context) {
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := postgresqlService.LoadStatus(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
|
@ -63,51 +63,6 @@ type PostgresqlDBDelete struct {
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
}
|
||||
|
||||
type PostgresqlStatus struct {
|
||||
Uptime string `json:"uptime"`
|
||||
Version string `json:"version"`
|
||||
MaxConnections string `json:"max_connections"`
|
||||
Autovacuum string `json:"autovacuum"`
|
||||
CurrentConnections string `json:"current_connections"`
|
||||
HitRatio string `json:"hit_ratio"`
|
||||
SharedBuffers string `json:"shared_buffers"`
|
||||
BuffersClean string `json:"buffers_clean"`
|
||||
MaxwrittenClean string `json:"maxwritten_clean"`
|
||||
BuffersBackendFsync string `json:"buffers_backend_fsync"`
|
||||
}
|
||||
|
||||
type PostgresqlVariables struct {
|
||||
BinlogCachSize string `json:"binlog_cache_size"`
|
||||
InnodbBufferPoolSize string `json:"innodb_buffer_pool_size"`
|
||||
InnodbLogBufferSize string `json:"innodb_log_buffer_size"`
|
||||
JoinBufferSize string `json:"join_buffer_size"`
|
||||
KeyBufferSize string `json:"key_buffer_size"`
|
||||
MaxConnections string `json:"max_connections"`
|
||||
MaxHeapTableSize string `json:"max_heap_table_size"`
|
||||
QueryCacheSize string `json:"query_cache_size"`
|
||||
QueryCache_type string `json:"query_cache_type"`
|
||||
ReadBufferSize string `json:"read_buffer_size"`
|
||||
ReadRndBufferSize string `json:"read_rnd_buffer_size"`
|
||||
SortBufferSize string `json:"sort_buffer_size"`
|
||||
TableOpenCache string `json:"table_open_cache"`
|
||||
ThreadCacheSize string `json:"thread_cache_size"`
|
||||
ThreadStack string `json:"thread_stack"`
|
||||
TmpTableSize string `json:"tmp_table_size"`
|
||||
|
||||
SlowQueryLog string `json:"slow_query_log"`
|
||||
LongQueryTime string `json:"long_query_time"`
|
||||
}
|
||||
|
||||
type PostgresqlVariablesUpdate struct {
|
||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Variables []PostgresqlVariablesUpdateHelper `json:"variables"`
|
||||
}
|
||||
|
||||
type PostgresqlVariablesUpdateHelper struct {
|
||||
Param string `json:"param"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
type PostgresqlConfUpdateByFile struct {
|
||||
Type string `json:"type" validate:"required,oneof=postgresql mariadb"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
|
@ -256,7 +256,6 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
}
|
||||
resourceId = pgdb.ID
|
||||
}
|
||||
break
|
||||
case "mysql", "mariadb":
|
||||
iMysqlRepo := repo.NewIMysqlRepo()
|
||||
oldMysqlDb, _ := iMysqlRepo.Get(commonRepo.WithByName(dbConfig.DbName), iMysqlRepo.WithByFrom(constant.ResourceLocal))
|
||||
@ -280,8 +279,6 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
}
|
||||
resourceId = mysqldb.ID
|
||||
}
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,14 +2,15 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
@ -97,18 +98,14 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
func handlePostgresqlBackup(database, dbName, targetDir, fileName string) error {
|
||||
dbInfo, err := postgresqlRepo.Get(commonRepo.WithByName(dbName), postgresqlRepo.WithByPostgresqlName(database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, _, err := LoadPostgresqlClientByFrom(database)
|
||||
cli, err := LoadPostgresqlClientByFrom(database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
backupInfo := pgclient.BackupInfo{
|
||||
Name: dbName,
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
|
||||
@ -130,16 +127,16 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, _, err := LoadPostgresqlClientByFrom(req.Name)
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
|
||||
if err := cli.Backup(client.BackupInfo{
|
||||
Name: req.DetailName,
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: path.Dir(rollbackFile),
|
||||
FileName: path.Base(rollbackFile),
|
||||
|
||||
@ -152,7 +149,6 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := cli.Recover(client.RecoverInfo{
|
||||
Name: req.DetailName,
|
||||
Format: dbInfo.Format,
|
||||
SourceFile: rollbackFile,
|
||||
|
||||
Timeout: 300,
|
||||
@ -168,10 +164,9 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
}
|
||||
if err := cli.Recover(client.RecoverInfo{
|
||||
Name: req.DetailName,
|
||||
Format: dbInfo.Format,
|
||||
SourceFile: req.File,
|
||||
Username: dbInfo.Username,
|
||||
Timeout: 300,
|
||||
Username: dbInfo.Username,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -3,11 +3,12 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
|
||||
client2 "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
|
||||
client2 "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@ -88,13 +89,7 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
|
||||
SSL: false,
|
||||
RootCert: req.RootCert,
|
||||
ClientKey: req.ClientKey,
|
||||
ClientCert: req.ClientCert,
|
||||
SkipVerify: req.SkipVerify,
|
||||
Timeout: 6,
|
||||
Timeout: 6,
|
||||
})
|
||||
return err == nil
|
||||
case "mysql", "mariadb":
|
||||
@ -134,13 +129,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
|
||||
SSL: req.SSL,
|
||||
RootCert: req.RootCert,
|
||||
ClientKey: req.ClientKey,
|
||||
ClientCert: req.ClientCert,
|
||||
SkipVerify: req.SkipVerify,
|
||||
Timeout: 6,
|
||||
Timeout: 6,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -230,13 +219,7 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
|
||||
SSL: req.SSL,
|
||||
RootCert: req.RootCert,
|
||||
ClientKey: req.ClientKey,
|
||||
ClientCert: req.ClientCert,
|
||||
SkipVerify: req.SkipVerify,
|
||||
Timeout: 300,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -4,6 +4,10 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
@ -17,8 +21,6 @@ import (
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
type PostgresqlService struct{}
|
||||
@ -28,19 +30,13 @@ type IPostgresqlService interface {
|
||||
ListDBOption() ([]dto.PostgresqlOption, error)
|
||||
Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error)
|
||||
LoadFromRemote(req dto.PostgresqlLoadDB) error
|
||||
ChangeAccess(info dto.ChangeDBInfo) error
|
||||
ChangePassword(info dto.ChangeDBInfo) error
|
||||
UpdateVariables(req dto.PostgresqlVariablesUpdate) error
|
||||
UpdateConfByFile(info dto.PostgresqlConfUpdateByFile) error
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
DeleteCheck(req dto.PostgresqlDBDeleteCheck) ([]string, error)
|
||||
Delete(ctx context.Context, req dto.PostgresqlDBDelete) error
|
||||
|
||||
LoadStatus(req dto.OperationWithNameAndType) (*dto.PostgresqlStatus, error)
|
||||
LoadVariables(req dto.OperationWithNameAndType) (*dto.PostgresqlVariables, error)
|
||||
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
|
||||
LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error)
|
||||
|
||||
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
|
||||
}
|
||||
|
||||
@ -111,18 +107,18 @@ func (u *PostgresqlService) Create(ctx context.Context, req dto.PostgresqlDBCrea
|
||||
return nil, errors.New("Cannot set root as user name")
|
||||
}
|
||||
|
||||
cli, version, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
createItem.PostgresqlName = req.Database
|
||||
defer cli.Close()
|
||||
if err := cli.Create(client.CreateInfo{
|
||||
Name: req.Name,
|
||||
Format: req.Format,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Version: version,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@ -134,17 +130,17 @@ func (u *PostgresqlService) Create(ctx context.Context, req dto.PostgresqlDBCrea
|
||||
}
|
||||
return &createItem, nil
|
||||
}
|
||||
func LoadPostgresqlClientByFrom(database string) (postgresql.PostgresqlClient, string, error) {
|
||||
|
||||
func LoadPostgresqlClientByFrom(database string) (postgresql.PostgresqlClient, error) {
|
||||
var (
|
||||
dbInfo client.DBInfo
|
||||
version string
|
||||
err error
|
||||
dbInfo client.DBInfo
|
||||
err error
|
||||
)
|
||||
|
||||
dbInfo.Timeout = 300
|
||||
databaseItem, err := databaseRepo.Get(commonRepo.WithByName(database))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
dbInfo.From = databaseItem.From
|
||||
dbInfo.Database = database
|
||||
@ -153,17 +149,10 @@ func LoadPostgresqlClientByFrom(database string) (postgresql.PostgresqlClient, s
|
||||
dbInfo.Port = databaseItem.Port
|
||||
dbInfo.Username = databaseItem.Username
|
||||
dbInfo.Password = databaseItem.Password
|
||||
dbInfo.SSL = databaseItem.SSL
|
||||
dbInfo.ClientKey = databaseItem.ClientKey
|
||||
dbInfo.ClientCert = databaseItem.ClientCert
|
||||
dbInfo.RootCert = databaseItem.RootCert
|
||||
dbInfo.SkipVerify = databaseItem.SkipVerify
|
||||
version = databaseItem.Version
|
||||
|
||||
} else {
|
||||
app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, database)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
dbInfo.From = "local"
|
||||
dbInfo.Address = app.ContainerName
|
||||
@ -174,12 +163,44 @@ func LoadPostgresqlClientByFrom(database string) (postgresql.PostgresqlClient, s
|
||||
|
||||
cli, err := postgresql.NewPostgresqlClient(dbInfo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
return cli, version, nil
|
||||
return cli, nil
|
||||
}
|
||||
func (u *PostgresqlService) LoadFromRemote(req dto.PostgresqlLoadDB) error {
|
||||
|
||||
func (u *PostgresqlService) LoadFromRemote(req dto.PostgresqlLoadDB) error {
|
||||
client, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
databases, err := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(req.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
datas, err := client.SyncDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, data := range datas {
|
||||
hasOld := false
|
||||
for _, oldData := range databases {
|
||||
if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.PostgresqlName, data.PostgresqlName) {
|
||||
hasOld = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasOld {
|
||||
var createItem model.DatabasePostgresql
|
||||
if err := copier.Copy(&createItem, &data); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if err := postgresqlRepo.Create(context.Background(), &createItem); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -224,17 +245,16 @@ func (u *PostgresqlService) Delete(ctx context.Context, req dto.PostgresqlDBDele
|
||||
if err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
cli, version, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
if err := cli.Delete(client.DeleteInfo{
|
||||
Name: db.Name,
|
||||
Version: version,
|
||||
Username: db.Username,
|
||||
Permission: "",
|
||||
Timeout: 300,
|
||||
Name: db.Name,
|
||||
Username: db.Username,
|
||||
ForceDelete: req.ForceDelete,
|
||||
Timeout: 300,
|
||||
}); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
@ -264,7 +284,7 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(req.Value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
cli, version, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -275,14 +295,12 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
)
|
||||
passwordInfo.Password = req.Value
|
||||
passwordInfo.Timeout = 300
|
||||
passwordInfo.Version = version
|
||||
|
||||
if req.ID != 0 {
|
||||
postgresqlData, err = postgresqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
passwordInfo.Name = postgresqlData.Name
|
||||
passwordInfo.Username = postgresqlData.Username
|
||||
} else {
|
||||
dbItem, err := databaseRepo.Get(commonRepo.WithByType(req.Type), commonRepo.WithByFrom(req.From))
|
||||
@ -317,7 +335,7 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
}
|
||||
|
||||
global.LOG.Infof("start to update postgresql password used by app %s-%s", appModel.Key, appInstall.Name)
|
||||
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, req.Value); err != nil {
|
||||
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "password", true, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -336,45 +354,6 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) ChangeAccess(req dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(req.Value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
cli, version, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
var (
|
||||
postgresqlData model.DatabasePostgresql
|
||||
accessInfo client.AccessChangeInfo
|
||||
)
|
||||
accessInfo.Permission = req.Value
|
||||
accessInfo.Timeout = 300
|
||||
accessInfo.Version = version
|
||||
|
||||
if req.ID != 0 {
|
||||
postgresqlData, err = postgresqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessInfo.Name = postgresqlData.Name
|
||||
accessInfo.Username = postgresqlData.Username
|
||||
accessInfo.Password = postgresqlData.Password
|
||||
} else {
|
||||
accessInfo.Username = "root"
|
||||
}
|
||||
if err := cli.ChangeAccess(accessInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if postgresqlData.ID != 0 {
|
||||
_ = postgresqlRepo.Update(postgresqlData.ID, map[string]interface{}{"permission": req.Value})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) UpdateConfByFile(req dto.PostgresqlConfUpdateByFile) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
@ -389,22 +368,12 @@ func (u *PostgresqlService) UpdateConfByFile(req dto.PostgresqlConfUpdateByFile)
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
cli, _, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) UpdateVariables(req dto.PostgresqlVariablesUpdate) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
|
||||
var data dto.DBBaseInfo
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
@ -418,32 +387,6 @@ func (u *PostgresqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) {
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.PostgresqlVariables, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.PostgresqlStatus, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cli, _, err := LoadPostgresqlClientByFrom(app.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
status := cli.Status()
|
||||
postgresqlStatus := dto.PostgresqlStatus{}
|
||||
copier.Copy(&postgresqlStatus,&status)
|
||||
return &postgresqlStatus, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
|
||||
filePath := ""
|
||||
switch req.Type {
|
||||
|
@ -53,15 +53,13 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
cmdRouter.POST("/db/del/check", baseApi.DeleteCheckDatabase)
|
||||
cmdRouter.POST("/db/del", baseApi.DeleteDatabase)
|
||||
|
||||
//PGSQL管理系列接口
|
||||
cmdRouter.POST("/pg", baseApi.CreatePostgresql)
|
||||
cmdRouter.POST("/pg/search", baseApi.SearchPostgresql)
|
||||
cmdRouter.POST("/pg/load", baseApi.LoadPostgresqlDBFromRemote)
|
||||
cmdRouter.POST("/pg/del/check", baseApi.DeleteCheckPostgresql)
|
||||
cmdRouter.POST("/pg/password", baseApi.ChangePostgresqlPassword)
|
||||
cmdRouter.POST("/pg/description", baseApi.UpdatePostgresqlDescription)
|
||||
cmdRouter.POST("/pg/del", baseApi.DeletePostgresql)
|
||||
cmdRouter.POST("/pg/conf", baseApi.UpdatePostgresqlConfByFile)
|
||||
cmdRouter.POST("/pg/status", baseApi.LoadPostgresqlStatus)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -63,13 +63,15 @@ func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "error 1396") {
|
||||
return buserr.New(constant.ErrUserIsExist)
|
||||
}
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to %s", info.Name, user)
|
||||
@ -82,13 +84,15 @@ func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
|
||||
grantStr = grantStr + " with grant option;"
|
||||
}
|
||||
if err := r.ExecSQL(grantStr, info.Timeout); err != nil {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -4,34 +4,32 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PostgresqlClient interface {
|
||||
Create(info client.CreateInfo) error
|
||||
Delete(info client.DeleteInfo) error
|
||||
ReloadConf()error
|
||||
ReloadConf() error
|
||||
ChangePassword(info client.PasswordChangeInfo) error
|
||||
ChangeAccess(info client.AccessChangeInfo) error
|
||||
|
||||
Backup(info client.BackupInfo) error
|
||||
Recover(info client.RecoverInfo) error
|
||||
Status() client.Status
|
||||
SyncDB(version string) ([]client.SyncDBInfo, error)
|
||||
SyncDB() ([]client.SyncDBInfo, error)
|
||||
Close()
|
||||
}
|
||||
|
||||
func NewPostgresqlClient(conn client.DBInfo) (PostgresqlClient, error) {
|
||||
if conn.Port==0 {
|
||||
conn.Port=5432
|
||||
}
|
||||
if conn.From == "local" {
|
||||
conn.Address = "127.0.0.1"
|
||||
connArgs := []string{"exec", conn.Address, "psql", "-U", conn.Username, "-c"}
|
||||
return client.NewLocal(connArgs, conn.Address, conn.Username, conn.Password, conn.Database), nil
|
||||
}
|
||||
|
||||
connArgs := fmt.Sprintf("postgres://%s:%s@%s:%d/?sslmode=disable", conn.Username, conn.Password, conn.Address, conn.Port)
|
||||
db, err := sql.Open("pgx", connArgs)
|
||||
if err != nil {
|
||||
@ -54,11 +52,5 @@ func NewPostgresqlClient(conn client.DBInfo) (PostgresqlClient, error) {
|
||||
Password: conn.Password,
|
||||
Address: conn.Address,
|
||||
Port: conn.Port,
|
||||
|
||||
SSL: conn.SSL,
|
||||
RootCert: conn.RootCert,
|
||||
ClientKey: conn.ClientKey,
|
||||
ClientCert: conn.ClientCert,
|
||||
SkipVerify: conn.SkipVerify,
|
||||
}), nil
|
||||
}
|
||||
|
@ -12,60 +12,34 @@ type DBInfo struct {
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert"`
|
||||
ClientKey string `json:"clientKey"`
|
||||
ClientCert string `json:"clientCert"`
|
||||
SkipVerify bool `json:"skipVerify"`
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
type CreateInfo struct {
|
||||
Name string `json:"name"`
|
||||
Format string `json:"format"`
|
||||
Version string `json:"version"`
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
Permission string `json:"permission"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
type DeleteInfo struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Username string `json:"userName"`
|
||||
Permission string `json:"permission"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"userName"`
|
||||
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
type PasswordChangeInfo struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
Permission string `json:"permission"`
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
type AccessChangeInfo struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
OldPermission string `json:"oldPermission"`
|
||||
Permission string `json:"permission"`
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
type BackupInfo struct {
|
||||
Name string `json:"name"`
|
||||
Format string `json:"format"`
|
||||
TargetDir string `json:"targetDir"`
|
||||
FileName string `json:"fileName"`
|
||||
|
||||
@ -74,19 +48,16 @@ type BackupInfo struct {
|
||||
|
||||
type RecoverInfo struct {
|
||||
Name string `json:"name"`
|
||||
Format string `json:"format"`
|
||||
SourceFile string `json:"sourceFile"`
|
||||
Username string `json:"username"`
|
||||
Timeout uint `json:"timeout"` // second
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
type SyncDBInfo struct {
|
||||
Name string `json:"name"`
|
||||
From string `json:"from"`
|
||||
PostgresqlName string `json:"postgresqlName"`
|
||||
Format string `json:"format"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
type Status struct {
|
||||
Uptime string `json:"uptime"`
|
||||
|
201
backend/utils/postgresql/client/local.go
Normal file
201
backend/utils/postgresql/client/local.go
Normal file
@ -0,0 +1,201 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
type Local struct {
|
||||
PrefixCommand []string
|
||||
Database string
|
||||
Username string
|
||||
Password string
|
||||
ContainerName string
|
||||
}
|
||||
|
||||
func NewLocal(command []string, containerName, username, password, database string) *Local {
|
||||
return &Local{PrefixCommand: command, ContainerName: containerName, Username: username, Password: password, Database: database}
|
||||
}
|
||||
|
||||
func (r *Local) Create(info CreateInfo) error {
|
||||
createSql := fmt.Sprintf("CREATE DATABASE %s", info.Name)
|
||||
if err := r.ExecSQL(createSql, info.Timeout); err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already exists") {
|
||||
return buserr.New(constant.ErrDatabaseIsExist)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.CreateUser(info, true); err != nil {
|
||||
_ = r.ExecSQL(fmt.Sprintf("DROP DATABASE %s", info.Name), info.Timeout)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
|
||||
createSql := fmt.Sprintf("CREATE USER \"%s\" WITH PASSWORD '%s'", info.Username, info.Username)
|
||||
if err := r.ExecSQL(createSql, info.Timeout); err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already exists") {
|
||||
return buserr.New(constant.ErrUserIsExist)
|
||||
}
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Username: info.Username,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
grantStr := fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", info.Name, info.Username)
|
||||
if err := r.ExecSQL(grantStr, info.Timeout); err != nil {
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Username: info.Username,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) Delete(info DeleteInfo) error {
|
||||
if len(info.Name) != 0 {
|
||||
dropSql := fmt.Sprintf("DROP DATABASE %s", info.Name)
|
||||
if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dropSql := fmt.Sprintf("DROP ROLE %s", info.Username)
|
||||
if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "depend on it") {
|
||||
return buserr.WithDetail(constant.ErrInUsed, info.Username, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) ChangePassword(info PasswordChangeInfo) error {
|
||||
changeSql := fmt.Sprintf("ALTER USER \"%s\" WITH PASSWORD '%s'", info.Username, info.Password)
|
||||
if err := r.ExecSQL(changeSql, info.Timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) Backup(info BackupInfo) error {
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(info.TargetDir) {
|
||||
if err := os.MkdirAll(info.TargetDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", info.TargetDir, err)
|
||||
}
|
||||
}
|
||||
outfile, _ := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
global.LOG.Infof("start to pg_dump | gzip > %s.gzip", info.TargetDir+"/"+info.FileName)
|
||||
cmd := exec.Command("docker", "exec", r.ContainerName, "pg_dump", "-F", "c", "-U", r.Username, "-d", info.Name)
|
||||
gzipCmd := exec.Command("gzip", "-cf")
|
||||
gzipCmd.Stdin, _ = cmd.StdoutPipe()
|
||||
gzipCmd.Stdout = outfile
|
||||
_ = gzipCmd.Start()
|
||||
_ = cmd.Run()
|
||||
_ = gzipCmd.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) Recover(info RecoverInfo) error {
|
||||
fi, _ := os.Open(info.SourceFile)
|
||||
defer fi.Close()
|
||||
cmd := exec.Command("docker", "exec", "-i", r.ContainerName, "pg_restore", "-F", "c", "-c", "-U", r.Username, "-d", info.Name)
|
||||
if strings.HasSuffix(info.SourceFile, ".gz") {
|
||||
gzipFile, err := os.Open(info.SourceFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzipFile.Close()
|
||||
gzipReader, err := gzip.NewReader(gzipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
cmd.Stdin = gzipReader
|
||||
} else {
|
||||
cmd.Stdin = fi
|
||||
}
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil || strings.HasPrefix(string(stdout), "ERROR ") {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) ReloadConf() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) SyncDB() ([]SyncDBInfo, error) {
|
||||
var datas []SyncDBInfo
|
||||
lines, err := r.ExecSQLForRows("SELECT datname FROM pg_database", 300)
|
||||
if err != nil {
|
||||
return datas, err
|
||||
}
|
||||
for _, line := range lines {
|
||||
if line == "postgres" || line == "template1" || line == "template0" || line == r.Username {
|
||||
continue
|
||||
}
|
||||
datas = append(datas, SyncDBInfo{Name: line, From: "local", PostgresqlName: r.Database})
|
||||
}
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func (r *Local) Close() {}
|
||||
|
||||
func (r *Local) ExecSQL(command string, timeout uint) error {
|
||||
itemCommand := r.PrefixCommand[:]
|
||||
itemCommand = append(itemCommand, command)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "docker", itemCommand...)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
return buserr.New(constant.ErrExecTimeOut)
|
||||
}
|
||||
if err != nil || strings.HasPrefix(string(stdout), "ERROR ") {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) ExecSQLForRows(command string, timeout uint) ([]string, error) {
|
||||
itemCommand := r.PrefixCommand[:]
|
||||
itemCommand = append(itemCommand, command)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "docker", itemCommand...)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
return nil, buserr.New(constant.ErrExecTimeOut)
|
||||
}
|
||||
if err != nil || strings.HasPrefix(string(stdout), "ERROR ") {
|
||||
return nil, errors.New(string(stdout))
|
||||
}
|
||||
return strings.Split(string(stdout), "\n"), nil
|
||||
}
|
@ -5,14 +5,15 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/pkg/errors"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
@ -21,115 +22,83 @@ import (
|
||||
|
||||
type Remote struct {
|
||||
Client *sql.DB
|
||||
From string
|
||||
Database string
|
||||
User string
|
||||
Password string
|
||||
Address string
|
||||
Port uint
|
||||
|
||||
SSL bool
|
||||
RootCert string
|
||||
ClientKey string
|
||||
ClientCert string
|
||||
SkipVerify bool
|
||||
}
|
||||
|
||||
func NewRemote(db Remote) *Remote {
|
||||
return &db
|
||||
}
|
||||
func (r *Remote) Status() Status {
|
||||
status := Status{}
|
||||
var i int64
|
||||
var s string
|
||||
var f float64
|
||||
_ = r.Client.QueryRow("select count(*) from pg_stat_activity WHERE client_addr is not NULL;").Scan(&i)
|
||||
status.CurrentConnections = fmt.Sprintf("%d",i)
|
||||
_ = r.Client.QueryRow("SELECT current_timestamp - pg_postmaster_start_time();").Scan(&s)
|
||||
before,_, _ := strings.Cut(s, ".")
|
||||
status.Uptime = before
|
||||
_ = r.Client.QueryRow("select sum(blks_hit)*100/sum(blks_hit+blks_read) as hit_ratio from pg_stat_database;").Scan(&f)
|
||||
status.HitRatio = fmt.Sprintf("%0.2f",f)
|
||||
var a1,a2,a3 int64
|
||||
_ = r.Client.QueryRow("select buffers_clean, maxwritten_clean, buffers_backend_fsync from pg_stat_bgwriter;").Scan(&a1, &a2, &a3)
|
||||
status.BuffersClean = fmt.Sprintf("%d",a1)
|
||||
status.MaxwrittenClean = fmt.Sprintf("%d",a2)
|
||||
status.BuffersBackendFsync= fmt.Sprintf("%d",a3)
|
||||
rows, err := r.Client.Query("SHOW ALL;")
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var k,v string
|
||||
err := rows.Scan(&k, &v,&s)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if k == "autovacuum" {
|
||||
status.Autovacuum = v
|
||||
}
|
||||
if k == "max_connections" {
|
||||
status.MaxConnections = v
|
||||
}
|
||||
if k == "server_version" {
|
||||
status.Version = v
|
||||
}
|
||||
if k == "shared_buffers" {
|
||||
status.SharedBuffers = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
func (r *Remote) Create(info CreateInfo) error {
|
||||
createUser := fmt.Sprintf(`CREATE USER "%s" WITH PASSWORD '%s';`, info.Username, info.Password)
|
||||
createDB := fmt.Sprintf(`CREATE DATABASE "%s" OWNER "%s";`, info.Name, info.Username)
|
||||
grant := fmt.Sprintf(`GRANT ALL PRIVILEGES ON DATABASE "%s" TO "%s";`, info.Name, info.Username)
|
||||
if err := r.ExecSQL(createUser, info.Timeout); err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already") {
|
||||
return buserr.New(constant.ErrUserIsExist)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := r.ExecSQL(createDB, info.Timeout); err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already") {
|
||||
_ = r.ExecSQL(fmt.Sprintf(`DROP DATABASE "%s"`, info.Name), info.Timeout)
|
||||
createSql := fmt.Sprintf("CREATE DATABASE %s", info.Name)
|
||||
if err := r.ExecSQL(createSql, info.Timeout); err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already exists") {
|
||||
return buserr.New(constant.ErrDatabaseIsExist)
|
||||
}
|
||||
return err
|
||||
}
|
||||
_ = r.ExecSQL(grant, info.Timeout)
|
||||
if err := r.CreateUser(info, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error {
|
||||
sql1 := fmt.Sprintf(`CREATE USER "%s" WITH PASSWORD '%s';
|
||||
GRANT ALL PRIVILEGES ON DATABASE "%s" TO "%s";`, info.Username, info.Password, info.Name, info.Username)
|
||||
err := r.ExecSQL(sql1, info.Timeout)
|
||||
if err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already") {
|
||||
createSql := fmt.Sprintf("CREATE USER \"%s\" WITH PASSWORD '%s'", info.Username, info.Password)
|
||||
if err := r.ExecSQL(createSql, info.Timeout); err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "already exists") {
|
||||
return buserr.New(constant.ErrUserIsExist)
|
||||
}
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Username: info.Username,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
grantSql := fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", info.Name, info.Username)
|
||||
if err := r.ExecSQL(grantSql, info.Timeout); err != nil {
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Username: info.Username,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Remote) Delete(info DeleteInfo) error {
|
||||
//暂时不支持强制删除,就算附加了 WITH(FORCE) 也会删除失败
|
||||
err := r.ExecSQL(fmt.Sprintf(`DROP DATABASE "%s"`, info.Name), info.Timeout)
|
||||
if err != nil {
|
||||
if len(info.Name) != 0 {
|
||||
dropSql := fmt.Sprintf("DROP DATABASE %s", info.Name)
|
||||
if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dropSql := fmt.Sprintf("DROP ROLE %s", info.Username)
|
||||
if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "depend on it") {
|
||||
return buserr.WithDetail(constant.ErrInUsed, info.Username, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return r.ExecSQL(fmt.Sprintf(`DROP USER "%s"`, info.Username), info.Timeout)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
|
||||
return r.ExecSQL(fmt.Sprintf(`ALTER USER "%s" WITH ENCRYPTED PASSWORD '%s';`, info.Username, info.Password), info.Timeout)
|
||||
return r.ExecSQL(fmt.Sprintf("ALTER USER \"%s\" WITH ENCRYPTED PASSWORD '%s'", info.Username, info.Password), info.Timeout)
|
||||
}
|
||||
func (r *Remote) ReloadConf()error {
|
||||
return r.ExecSQL("SELECT pg_reload_conf();",5)
|
||||
}
|
||||
func (r *Remote) ChangeAccess(info AccessChangeInfo) error {
|
||||
return nil
|
||||
func (r *Remote) ReloadConf() error {
|
||||
return r.ExecSQL("SELECT pg_reload_conf()", 5)
|
||||
}
|
||||
|
||||
func (r *Remote) Backup(info BackupInfo) error {
|
||||
@ -173,7 +142,7 @@ func (r *Remote) Recover(info RecoverInfo) error {
|
||||
gzipCmd := exec.Command("gunzip", info.SourceFile)
|
||||
stdout, err := gzipCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("gunzip file %s failed, stdout: %v, err: %v", info.SourceFile, string(stdout), err)
|
||||
return fmt.Errorf("gunzip file %s failed, stdout: %v, err: %v", info.SourceFile, string(stdout), err)
|
||||
}
|
||||
defer func() {
|
||||
gzipCmd := exec.Command("gzip", fileName)
|
||||
@ -207,9 +176,29 @@ func (r *Remote) Recover(info RecoverInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||
//如果需要同步数据库,则需要强制修改用户密码,否则无法获取真实密码,后面可考虑改为添加服务器账号,手动将账号/数据库添加到管理列表
|
||||
func (r *Remote) SyncDB() ([]SyncDBInfo, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var datas []SyncDBInfo
|
||||
rows, err := r.Client.Query("SELECT datname FROM pg_database;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var dbName string
|
||||
if err := rows.Scan(&dbName); err != nil {
|
||||
continue
|
||||
}
|
||||
if dbName == "postgres" || dbName == "template1" || dbName == "template0" || dbName == r.User {
|
||||
continue
|
||||
}
|
||||
datas = append(datas, SyncDBInfo{Name: dbName, From: r.From, PostgresqlName: r.Database})
|
||||
}
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
return nil, buserr.New(constant.ErrExecTimeOut)
|
||||
}
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
|
@ -4642,6 +4642,421 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "创建 postgresql 数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Create postgresql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "create postgresql database [name]",
|
||||
"formatZH": "创建 postgresql 数据库 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/baseinfo": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取 postgresql 基础信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Load postgresql base info",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.OperationWithNameAndType"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.DBBaseInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/conf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "上传替换 postgresql 配置文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Update postgresql conf by upload file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlConfUpdateByFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [],
|
||||
"formatEN": "update the postgresql database configuration information",
|
||||
"formatZH": "更新 postgresql 数据库配置信息",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/del": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "删除 postgresql 数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Delete postgresql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBDelete"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [
|
||||
{
|
||||
"db": "database_postgresqls",
|
||||
"input_column": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_column": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "delete postgresql database [name]",
|
||||
"formatZH": "删除 postgresql 数据库 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/del/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Postgresql 数据库删除前检查",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Check before delete postgresql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBDeleteCheck"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/description": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新 postgresql 数据库库描述信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Update postgresql database description",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpdateDescription"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [
|
||||
{
|
||||
"db": "database_postgresqls",
|
||||
"input_column": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_column": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id",
|
||||
"description"
|
||||
],
|
||||
"formatEN": "The description of the postgresql database [name] is modified =\u003e [description]",
|
||||
"formatZH": "postgresql 数据库 [name] 描述信息修改 [description]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/load": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从服务器获取",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Load postgresql database from remote",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlLoadDB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/databases/pg/options": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取 postgresql 数据库列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "List postgresql database names",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PageInfo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.PostgresqlOption"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/password": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改 postgresql 密码",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Change postgresql password",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ChangeDBInfo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [
|
||||
{
|
||||
"db": "database_postgresqls",
|
||||
"input_column": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_column": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update database [name] password",
|
||||
"formatZH": "更新数据库 [name] 密码",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取 postgresql 数据库列表分页",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Page postgresql databases",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBSearch"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PageResult"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/backup/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -13734,7 +14149,8 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mysql",
|
||||
"mariadb"
|
||||
"mariadb",
|
||||
"postgresql"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
@ -13871,7 +14287,8 @@ const docTemplate = `{
|
||||
"mysql",
|
||||
"mariadb",
|
||||
"redis",
|
||||
"website"
|
||||
"website",
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -13913,7 +14330,8 @@ const docTemplate = `{
|
||||
"mysql",
|
||||
"mariadb",
|
||||
"redis",
|
||||
"website"
|
||||
"website",
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -16388,6 +16806,193 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlConfUpdateByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql",
|
||||
"mariadb"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"from",
|
||||
"name",
|
||||
"password",
|
||||
"permission",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"local",
|
||||
"remote"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBDelete": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"deleteBackup": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"forceDelete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBDeleteCheck": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"page",
|
||||
"pageSize"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"info": {
|
||||
"type": "string"
|
||||
},
|
||||
"order": {
|
||||
"type": "string"
|
||||
},
|
||||
"orderBy": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pageSize": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlLoadDB": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"from",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"local",
|
||||
"remote"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlOption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RecordSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -4635,6 +4635,421 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "创建 postgresql 数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Create postgresql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "create postgresql database [name]",
|
||||
"formatZH": "创建 postgresql 数据库 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/baseinfo": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取 postgresql 基础信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Load postgresql base info",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.OperationWithNameAndType"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.DBBaseInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/conf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "上传替换 postgresql 配置文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Update postgresql conf by upload file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlConfUpdateByFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [],
|
||||
"formatEN": "update the postgresql database configuration information",
|
||||
"formatZH": "更新 postgresql 数据库配置信息",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/del": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "删除 postgresql 数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Delete postgresql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBDelete"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [
|
||||
{
|
||||
"db": "database_postgresqls",
|
||||
"input_column": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_column": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "delete postgresql database [name]",
|
||||
"formatZH": "删除 postgresql 数据库 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/del/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Postgresql 数据库删除前检查",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Check before delete postgresql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBDeleteCheck"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/description": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新 postgresql 数据库库描述信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Update postgresql database description",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpdateDescription"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [
|
||||
{
|
||||
"db": "database_postgresqls",
|
||||
"input_column": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_column": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id",
|
||||
"description"
|
||||
],
|
||||
"formatEN": "The description of the postgresql database [name] is modified =\u003e [description]",
|
||||
"formatZH": "postgresql 数据库 [name] 描述信息修改 [description]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/load": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从服务器获取",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Load postgresql database from remote",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlLoadDB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/databases/pg/options": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取 postgresql 数据库列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "List postgresql database names",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PageInfo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.PostgresqlOption"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/password": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改 postgresql 密码",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Change postgresql password",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ChangeDBInfo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [
|
||||
{
|
||||
"db": "database_postgresqls",
|
||||
"input_column": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_column": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update database [name] password",
|
||||
"formatZH": "更新数据库 [name] 密码",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/pg/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取 postgresql 数据库列表分页",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Postgresql"
|
||||
],
|
||||
"summary": "Page postgresql databases",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PostgresqlDBSearch"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.PageResult"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/backup/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -13727,7 +14142,8 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mysql",
|
||||
"mariadb"
|
||||
"mariadb",
|
||||
"postgresql"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
@ -13864,7 +14280,8 @@
|
||||
"mysql",
|
||||
"mariadb",
|
||||
"redis",
|
||||
"website"
|
||||
"website",
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -13906,7 +14323,8 @@
|
||||
"mysql",
|
||||
"mariadb",
|
||||
"redis",
|
||||
"website"
|
||||
"website",
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -16381,6 +16799,193 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlConfUpdateByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql",
|
||||
"mariadb"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"from",
|
||||
"name",
|
||||
"password",
|
||||
"permission",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"local",
|
||||
"remote"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBDelete": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"deleteBackup": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"forceDelete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBDeleteCheck": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlDBSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"page",
|
||||
"pageSize"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"info": {
|
||||
"type": "string"
|
||||
},
|
||||
"order": {
|
||||
"type": "string"
|
||||
},
|
||||
"orderBy": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pageSize": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlLoadDB": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"database",
|
||||
"from",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"local",
|
||||
"remote"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.PostgresqlOption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RecordSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -178,6 +178,7 @@ definitions:
|
||||
enum:
|
||||
- mysql
|
||||
- mariadb
|
||||
- postgresql
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
@ -272,6 +273,7 @@ definitions:
|
||||
- mariadb
|
||||
- redis
|
||||
- website
|
||||
- postgresql
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
@ -303,6 +305,7 @@ definitions:
|
||||
- mariadb
|
||||
- redis
|
||||
- website
|
||||
- postgresql
|
||||
type: string
|
||||
required:
|
||||
- source
|
||||
@ -1980,6 +1983,134 @@ definitions:
|
||||
required:
|
||||
- serverPort
|
||||
type: object
|
||||
dto.PostgresqlConfUpdateByFile:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
file:
|
||||
type: string
|
||||
type:
|
||||
enum:
|
||||
- postgresql
|
||||
- mariadb
|
||||
type: string
|
||||
required:
|
||||
- database
|
||||
- type
|
||||
type: object
|
||||
dto.PostgresqlDBCreate:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
format:
|
||||
type: string
|
||||
from:
|
||||
enum:
|
||||
- local
|
||||
- remote
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
permission:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
required:
|
||||
- database
|
||||
- from
|
||||
- name
|
||||
- password
|
||||
- permission
|
||||
- username
|
||||
type: object
|
||||
dto.PostgresqlDBDelete:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
deleteBackup:
|
||||
type: boolean
|
||||
forceDelete:
|
||||
type: boolean
|
||||
id:
|
||||
type: integer
|
||||
type:
|
||||
enum:
|
||||
- postgresql
|
||||
type: string
|
||||
required:
|
||||
- database
|
||||
- id
|
||||
- type
|
||||
type: object
|
||||
dto.PostgresqlDBDeleteCheck:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
type:
|
||||
enum:
|
||||
- postgresql
|
||||
type: string
|
||||
required:
|
||||
- database
|
||||
- id
|
||||
- type
|
||||
type: object
|
||||
dto.PostgresqlDBSearch:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
info:
|
||||
type: string
|
||||
order:
|
||||
type: string
|
||||
orderBy:
|
||||
type: string
|
||||
page:
|
||||
type: integer
|
||||
pageSize:
|
||||
type: integer
|
||||
required:
|
||||
- database
|
||||
- page
|
||||
- pageSize
|
||||
type: object
|
||||
dto.PostgresqlLoadDB:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
from:
|
||||
enum:
|
||||
- local
|
||||
- remote
|
||||
type: string
|
||||
type:
|
||||
enum:
|
||||
- postgresql
|
||||
type: string
|
||||
required:
|
||||
- database
|
||||
- from
|
||||
- type
|
||||
type: object
|
||||
dto.PostgresqlOption:
|
||||
properties:
|
||||
database:
|
||||
type: string
|
||||
from:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
dto.RecordSearch:
|
||||
properties:
|
||||
detailName:
|
||||
@ -7729,6 +7860,270 @@ paths:
|
||||
summary: List mysql database names
|
||||
tags:
|
||||
- Database Mysql
|
||||
/databases/pg:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建 postgresql 数据库
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PostgresqlDBCreate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Create postgresql database
|
||||
tags:
|
||||
- Database Postgresql
|
||||
x-panel-log:
|
||||
BeforeFunctions: []
|
||||
bodyKeys:
|
||||
- name
|
||||
formatEN: create postgresql database [name]
|
||||
formatZH: 创建 postgresql 数据库 [name]
|
||||
paramKeys: []
|
||||
/databases/pg/baseinfo:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取 postgresql 基础信息
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.OperationWithNameAndType'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.DBBaseInfo'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load postgresql base info
|
||||
tags:
|
||||
- Database Postgresql
|
||||
/databases/pg/conf:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 上传替换 postgresql 配置文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PostgresqlConfUpdateByFile'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update postgresql conf by upload file
|
||||
tags:
|
||||
- Database Postgresql
|
||||
x-panel-log:
|
||||
BeforeFunctions: []
|
||||
bodyKeys: []
|
||||
formatEN: update the postgresql database configuration information
|
||||
formatZH: 更新 postgresql 数据库配置信息
|
||||
paramKeys: []
|
||||
/databases/pg/del:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除 postgresql 数据库
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PostgresqlDBDelete'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Delete postgresql database
|
||||
tags:
|
||||
- Database Postgresql
|
||||
x-panel-log:
|
||||
BeforeFunctions:
|
||||
- db: database_postgresqls
|
||||
input_column: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_column: name
|
||||
output_value: name
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: delete postgresql database [name]
|
||||
formatZH: 删除 postgresql 数据库 [name]
|
||||
paramKeys: []
|
||||
/databases/pg/del/check:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Postgresql 数据库删除前检查
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PostgresqlDBDeleteCheck'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Check before delete postgresql database
|
||||
tags:
|
||||
- Database Postgresql
|
||||
/databases/pg/description:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新 postgresql 数据库库描述信息
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UpdateDescription'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update postgresql database description
|
||||
tags:
|
||||
- Database Postgresql
|
||||
x-panel-log:
|
||||
BeforeFunctions:
|
||||
- db: database_postgresqls
|
||||
input_column: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_column: name
|
||||
output_value: name
|
||||
bodyKeys:
|
||||
- id
|
||||
- description
|
||||
formatEN: The description of the postgresql database [name] is modified =>
|
||||
[description]
|
||||
formatZH: postgresql 数据库 [name] 描述信息修改 [description]
|
||||
paramKeys: []
|
||||
/databases/pg/load:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 从服务器获取
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PostgresqlLoadDB'
|
||||
responses: {}
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load postgresql database from remote
|
||||
tags:
|
||||
- Database Postgresql
|
||||
/databases/pg/options:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取 postgresql 数据库列表
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PageInfo'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/dto.PostgresqlOption'
|
||||
type: array
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: List postgresql database names
|
||||
tags:
|
||||
- Database Postgresql
|
||||
/databases/pg/password:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改 postgresql 密码
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.ChangeDBInfo'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Change postgresql password
|
||||
tags:
|
||||
- Database Postgresql
|
||||
x-panel-log:
|
||||
BeforeFunctions:
|
||||
- db: database_postgresqls
|
||||
input_column: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_column: name
|
||||
output_value: name
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: Update database [name] password
|
||||
formatZH: 更新数据库 [name] 密码
|
||||
paramKeys: []
|
||||
/databases/pg/search:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取 postgresql 数据库列表分页
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PostgresqlDBSearch'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.PageResult'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Page postgresql databases
|
||||
tags:
|
||||
- Database Postgresql
|
||||
/databases/redis/backup/search:
|
||||
post:
|
||||
consumes:
|
||||
|
@ -148,6 +148,11 @@ export namespace Database {
|
||||
database: string;
|
||||
name: string;
|
||||
}
|
||||
export interface PgLoadDB {
|
||||
from: string;
|
||||
type: string;
|
||||
database: string;
|
||||
}
|
||||
export interface PostgresqlDBDelete {
|
||||
id: number;
|
||||
type: string;
|
||||
|
@ -19,9 +19,6 @@ export const addPostgresqlDB = (params: Database.PostgresqlDBCreate) => {
|
||||
}
|
||||
return http.post(`/databases/pg`, request);
|
||||
};
|
||||
export const loadPostgresqlStatus = (type: string, database: string) => {
|
||||
return http.post<Database.PostgresqlStatus>(`/databases/pg/status`, { type: type, name: database });
|
||||
};
|
||||
export const updatePostgresqlConfByFile = (params: Database.PostgresqlConfUpdateByFile) => {
|
||||
return http.post(`/databases/pg/conf`, params);
|
||||
};
|
||||
@ -31,6 +28,9 @@ export const searchPostgresqlDBs = (params: Database.SearchDBWithPage) => {
|
||||
export const updatePostgresqlDescription = (params: DescriptionUpdate) => {
|
||||
return http.post(`/databases/pg/description`, params);
|
||||
};
|
||||
export const loadPgFromRemote = (params: Database.PgLoadDB) => {
|
||||
return http.post(`/databases/pg/load`, params);
|
||||
};
|
||||
export const deleteCheckPostgresqlDB = (params: Database.PostgresqlDBDeleteCheck) => {
|
||||
return http.post<Array<string>>(`/databases/pg/del/check`, params);
|
||||
};
|
||||
@ -44,6 +44,8 @@ export const updatePostgresqlPassword = (params: Database.ChangeInfo) => {
|
||||
export const deletePostgresqlDB = (params: Database.PostgresqlDBDelete) => {
|
||||
return http.post(`/databases/pg/del`, params);
|
||||
};
|
||||
|
||||
// mysql
|
||||
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
|
||||
let request = deepCopy(params) as Database.MysqlDBCreate;
|
||||
if (request.password) {
|
||||
|
@ -70,6 +70,14 @@
|
||||
>
|
||||
{{ $t('database.databaseConnInfo') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="currentDB && (currentDB.from !== 'local' || postgresqlStatus === 'Running')"
|
||||
@click="loadDB"
|
||||
type="primary"
|
||||
plain
|
||||
>
|
||||
{{ $t('database.loadFromRemote') }}
|
||||
</el-button>
|
||||
<el-button @click="goRemoteDB" type="primary" plain>
|
||||
{{ $t('database.remoteDB') }}
|
||||
</el-button>
|
||||
@ -218,6 +226,7 @@ import { onMounted, reactive, ref } from 'vue';
|
||||
import {
|
||||
deleteCheckPostgresqlDB,
|
||||
listDatabases,
|
||||
loadPgFromRemote,
|
||||
searchPostgresqlDBs,
|
||||
updatePostgresqlDescription,
|
||||
} from '@/api/modules/database';
|
||||
@ -343,6 +352,29 @@ const search = async (column?: any) => {
|
||||
paginationConfig.total = res.data.total;
|
||||
};
|
||||
|
||||
const loadDB = async () => {
|
||||
ElMessageBox.confirm(i18n.global.t('database.loadFromRemoteHelper'), i18n.global.t('commons.msg.infoTitle'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
}).then(async () => {
|
||||
loading.value = true;
|
||||
let params = {
|
||||
from: currentDB.value.from,
|
||||
type: currentDB.value.type,
|
||||
database: currentDBName.value,
|
||||
};
|
||||
await loadPgFromRemote(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
search();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const goRouter = async (target: string) => {
|
||||
if (target === 'app') {
|
||||
router.push({ name: 'AppAll', query: { install: 'postgresql' } });
|
||||
|
@ -7,14 +7,6 @@
|
||||
<el-button type="primary" :plain="activeName !== 'conf'" @click="jumpToConf">
|
||||
{{ $t('database.confChange') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="postgresqlStatus !== 'Running'"
|
||||
:plain="activeName !== 'status'"
|
||||
@click="activeName = 'status'"
|
||||
>
|
||||
{{ $t('database.currentStatus') }}
|
||||
</el-button>
|
||||
<el-button type="primary" :plain="activeName !== 'port'" @click="activeName = 'port'">
|
||||
{{ $t('commons.table.port') }}
|
||||
</el-button>
|
||||
@ -49,23 +41,10 @@
|
||||
:extensions="extensions"
|
||||
v-model="postgresqlConf"
|
||||
/>
|
||||
|
||||
<el-button type="primary" style="margin-top: 10px" @click="onSaveConf">
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-alert
|
||||
v-if="useOld"
|
||||
style="margin-top: 10px"
|
||||
:title="$t('app.defaultConfigHelper')"
|
||||
type="info"
|
||||
:closable="false"
|
||||
></el-alert>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<Status v-show="activeName === 'status'" ref="statusRef" />
|
||||
<div v-show="activeName === 'port'">
|
||||
<el-form :model="baseInfo" ref="panelFormRef" label-position="top">
|
||||
<el-row>
|
||||
@ -114,7 +93,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance } from 'element-plus';
|
||||
import ContainerLog from '@/components/container-log/index.vue';
|
||||
import Status from '@/views/database/postgresql/setting/status/index.vue';
|
||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
@ -143,10 +121,6 @@ const panelFormRef = ref<FormInstance>();
|
||||
const postgresqlConf = ref();
|
||||
const upgradeVisible = ref();
|
||||
|
||||
const useOld = ref(false);
|
||||
|
||||
const statusRef = ref();
|
||||
|
||||
const postgresqlName = ref();
|
||||
const postgresqlStatus = ref();
|
||||
const postgresqlVersion = ref();
|
||||
@ -214,7 +188,6 @@ const onSubmitChangeConf = async () => {
|
||||
loading.value = true;
|
||||
await updatePostgresqlConfByFile(param)
|
||||
.then(() => {
|
||||
useOld.value = false;
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
@ -247,7 +220,6 @@ const loadBaseInfo = async () => {
|
||||
};
|
||||
|
||||
const loadPostgresqlConf = async () => {
|
||||
useOld.value = false;
|
||||
await loadDatabaseFile(props.type + '-conf', props.database)
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
@ -269,9 +241,6 @@ const onLoadInfo = async () => {
|
||||
postgresqlStatus.value = res.data.status;
|
||||
postgresqlVersion.value = res.data.version;
|
||||
loadBaseInfo();
|
||||
if (postgresqlStatus.value === 'Running') {
|
||||
statusRef.value!.acceptParams({ type: props.type, database: props.database });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,168 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form label-position="top">
|
||||
<span class="title">{{ $t('database.baseParam') }}</span>
|
||||
<el-divider class="divider" />
|
||||
<el-row type="flex" justify="center" style="margin-left: 50px" :gutter="20">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('database.runTime') }}</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.uptime }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('database.connections') }}</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.max_connections }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('database.version') }}</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.version }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">AUTOVACUUM</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.autovacuum }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<span class="title">{{ $t('database.performanceParam') }}</span>
|
||||
<el-divider class="divider" />
|
||||
<el-row type="flex" style="margin-left: 50px" justify="center" :gutter="20">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('database.connInfo') }}</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.current_connections }}</span>
|
||||
<span class="input-help">{{ $t('database.connInfoHelper') }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('database.cacheHit') }}</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.hit_ratio }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item style="width: 25%"></el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item style="width: 25%"></el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">SHARED_BUFFERS</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.shared_buffers }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">BUFFERS_CLEAN</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.buffers_clean }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">MAXWRITTEN_CLEAN</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.maxwritten_clean }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="status-label">BUFFERS_BACKEND_FSYNC</span>
|
||||
</template>
|
||||
<span class="status-count">{{ postgresqlStatus.buffers_backend_fsync }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { loadPostgresqlStatus } from '@/api/modules/database';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
const postgresqlStatus = reactive({
|
||||
uptime: '',
|
||||
version: '',
|
||||
max_connections: '',
|
||||
autovacuum: '',
|
||||
current_connections: '',
|
||||
hit_ratio: '',
|
||||
shared_buffers: '',
|
||||
buffers_clean: '',
|
||||
maxwritten_clean: '',
|
||||
buffers_backend_fsync: '',
|
||||
});
|
||||
|
||||
const currentDB = reactive({
|
||||
type: '',
|
||||
database: '',
|
||||
});
|
||||
|
||||
interface DialogProps {
|
||||
type: string;
|
||||
database: string;
|
||||
}
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
currentDB.type = params.type;
|
||||
currentDB.database = params.database;
|
||||
loadStatus();
|
||||
};
|
||||
|
||||
const loadStatus = async () => {
|
||||
const res = await loadPostgresqlStatus(currentDB.type, currentDB.database);
|
||||
postgresqlStatus.uptime = res.data.uptime;
|
||||
postgresqlStatus.version = res.data.version;
|
||||
postgresqlStatus.max_connections = res.data.max_connections;
|
||||
postgresqlStatus.autovacuum = res.data.autovacuum;
|
||||
postgresqlStatus.current_connections = res.data.current_connections;
|
||||
postgresqlStatus.hit_ratio = res.data.hit_ratio;
|
||||
postgresqlStatus.shared_buffers = res.data.shared_buffers;
|
||||
postgresqlStatus.buffers_clean = res.data.buffers_clean;
|
||||
postgresqlStatus.maxwritten_clean = res.data.maxwritten_clean;
|
||||
postgresqlStatus.buffers_backend_fsync = res.data.buffers_backend_fsync;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.divider {
|
||||
display: block;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
margin: 12px 0;
|
||||
border-top: 1px var(--el-border-color) var(--el-border-style);
|
||||
}
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
margin-left: 50px;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user