1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 08:19:15 +08:00

feat: PostgreSQL 支持从服务器获取功能 (#3526)

This commit is contained in:
ssongliu 2024-01-08 17:40:42 +08:00 committed by GitHub
parent 2dc63e152b
commit 39818b8424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 804 additions and 935 deletions

View File

@ -227,31 +227,3 @@ func (b *BaseApi) UpdateDatabase(c *gin.Context) {
} }
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Database
// @Summary Load Database file
// @Description 获取数据库文件
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/load/file [post]
func (b *BaseApi) LoadDatabaseFile(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
var content string
var err error
switch req.Name {
case constant.AppPostgresql:
content, err = postgresqlService.LoadDatabaseFile(req)
default:
content, err = mysqlService.LoadDatabaseFile(req)
}
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}

View File

@ -0,0 +1,75 @@
package v1
import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin"
)
// @Tags Database Common
// @Summary Load base info
// @Description 获取数据库基础信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {object} dto.DBBaseInfo
// @Security ApiKeyAuth
// @Router /databases/common/info [post]
func (b *BaseApi) LoadDBBaseInfo(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := dbCommonService.LoadBaseInfo(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Database Common
// @Summary Load Database conf
// @Description 获取数据库配置文件
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/common/load/file [post]
func (b *BaseApi) LoadDBFile(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
content, err := dbCommonService.LoadDatabaseFile(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Database Common
// @Summary Update conf by upload file
// @Description 上传替换配置文件
// @Accept json
// @Param request body dto.DBConfUpdateByFile true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/common/update/conf [post]
// @x-panel-log {"bodyKeys":["type","database"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 [type] 数据库 [database] 配置信息","formatEN":"update the [type] [database] database configuration information"}
func (b *BaseApi) UpdateDBConfByFile(c *gin.Context) {
var req dto.DBConfUpdateByFile
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := dbCommonService.UpdateConfByFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@ -169,29 +169,6 @@ func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Database Mysql
// @Summary Update mysql conf by upload file
// @Description 上传替换 mysql 配置文件
// @Accept json
// @Param request body dto.MysqlConfUpdateByFile true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 mysql 数据库配置信息","formatEN":"update the mysql database configuration information"}
func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
var req dto.MysqlConfUpdateByFile
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := mysqlService.UpdateConfByFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Database Mysql // @Tags Database Mysql
// @Summary Page mysql databases // @Summary Page mysql databases
// @Description 获取 mysql 数据库列表分页 // @Description 获取 mysql 数据库列表分页
@ -304,29 +281,6 @@ func (b *BaseApi) DeleteMysql(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Database Mysql
// @Summary Load mysql base info
// @Description 获取 mysql 基础信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {object} dto.DBBaseInfo
// @Security ApiKeyAuth
// @Router /databases/baseinfo [post]
func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := mysqlService.LoadBaseInfo(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Database Mysql // @Tags Database Mysql
// @Summary Load mysql remote access // @Summary Load mysql remote access
// @Description 获取 mysql 远程访问权限 // @Description 获取 mysql 远程访问权限

View File

@ -41,6 +41,28 @@ func (b *BaseApi) CreatePostgresql(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Database Postgresql
// @Summary Bind postgresql user
// @Description 绑定 postgresql 数据库用户
// @Accept json
// @Param request body dto.PostgresqlBindUser true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/pg/bind [post]
// @x-panel-log {"bodyKeys":["name", "username"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"绑定 postgresql 数据库 [name] 用户 [username]","formatEN":"bind postgresql database [name] user [username]"}
func (b *BaseApi) BindPostgresqlUser(c *gin.Context) {
var req dto.PostgresqlBindUser
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := postgresqlService.BindUser(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Database Postgresql // @Tags Database Postgresql
// @Summary Update postgresql database description // @Summary Update postgresql database description
// @Description 更新 postgresql 数据库库描述信息 // @Description 更新 postgresql 数据库库描述信息
@ -94,29 +116,6 @@ func (b *BaseApi) ChangePostgresqlPassword(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Database Postgresql
// @Summary Update postgresql conf by upload file
// @Description 上传替换 postgresql 配置文件
// @Accept json
// @Param request body dto.PostgresqlConfUpdateByFile true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/pg/conf [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 postgresql 数据库配置信息","formatEN":"update the postgresql database configuration information"}
func (b *BaseApi) UpdatePostgresqlConfByFile(c *gin.Context) {
var req dto.PostgresqlConfUpdateByFile
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := postgresqlService.UpdateConfByFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Database Postgresql // @Tags Database Postgresql
// @Summary Page postgresql databases // @Summary Page postgresql databases
// @Description 获取 postgresql 数据库列表分页 // @Description 获取 postgresql 数据库列表分页
@ -167,21 +166,20 @@ func (b *BaseApi) ListPostgresqlDBName(c *gin.Context) {
// @Accept json // @Accept json
// @Param request body dto.PostgresqlLoadDB true "request" // @Param request body dto.PostgresqlLoadDB true "request"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/pg/load [post] // @Router /databases/pg/:database/load [post]
func (b *BaseApi) LoadPostgresqlDBFromRemote(c *gin.Context) { func (b *BaseApi) LoadPostgresqlDBFromRemote(c *gin.Context) {
var req dto.PostgresqlLoadDB database, err := helper.GetStrParamByKey(c, "database")
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
if err := postgresqlService.LoadFromRemote(req); err != nil { if err := postgresqlService.LoadFromRemote(database); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
helper.SuccessWithData(c, nil)
} }
// @Tags Database Postgresql // @Tags Database Postgresql
@ -229,26 +227,3 @@ func (b *BaseApi) DeletePostgresql(c *gin.Context) {
tx.Commit() tx.Commit()
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Database Postgresql
// @Summary Load postgresql base info
// @Description 获取 postgresql 基础信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {object} dto.DBBaseInfo
// @Security ApiKeyAuth
// @Router /databases/pg/baseinfo [post]
func (b *BaseApi) LoadPostgresqlBaseinfo(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := postgresqlService.LoadBaseInfo(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

View File

@ -1,15 +1,11 @@
package v1 package v1
import ( import (
"bufio"
"encoding/base64" "encoding/base64"
"fmt"
"os"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -161,45 +157,3 @@ func (b *BaseApi) RedisBackupList(c *gin.Context) {
Total: total, Total: total,
}) })
} }
// @Tags Database Redis
// @Summary Update redis conf by file
// @Description 上传更新 redis 配置信息
// @Accept json
// @Param request body dto.RedisConfUpdateByFile true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/redis/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 redis 数据库配置信息","formatEN":"update the redis database configuration information"}
func (b *BaseApi) UpdateRedisConfByFile(c *gin.Context) {
var req dto.RedisConfUpdateByFile
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
redisInfo, err := redisService.LoadConf()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisInfo.Name)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
if req.RestartNow {
composeDir := fmt.Sprintf("%s/redis/%s/docker-compose.yml", constant.AppInstallDir, redisInfo.Name)
if _, err := compose.Restart(composeDir); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
}
helper.SuccessWithData(c, nil)
}

View File

@ -21,6 +21,7 @@ var (
imageService = service.NewIImageService() imageService = service.NewIImageService()
dockerService = service.NewIDockerService() dockerService = service.NewIDockerService()
dbCommonService = service.NewIDBCommonService()
mysqlService = service.NewIMysqlService() mysqlService = service.NewIMysqlService()
postgresqlService = service.NewIPostgresqlService() postgresqlService = service.NewIPostgresqlService()
databaseService = service.NewIDatabaseService() databaseService = service.NewIDatabaseService()

View File

@ -2,6 +2,27 @@ package dto
import "time" import "time"
// common
type DBConfUpdateByFile struct {
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql redis"`
Database string `json:"database" validate:"required"`
File string `json:"file"`
}
type ChangeDBInfo struct {
ID uint `json:"id"`
From string `json:"from" validate:"required,oneof=local remote"`
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql"`
Database string `json:"database" validate:"required"`
Value string `json:"value" validate:"required"`
}
type DBBaseInfo struct {
Name string `json:"name"`
ContainerName string `json:"containerName"`
Port int64 `json:"port"`
}
// mysql
type MysqlDBSearch struct { type MysqlDBSearch struct {
PageInfo PageInfo
Info string `json:"info"` Info string `json:"info"`
@ -141,24 +162,6 @@ type MysqlVariablesUpdateHelper struct {
Param string `json:"param"` Param string `json:"param"`
Value interface{} `json:"value"` Value interface{} `json:"value"`
} }
type MysqlConfUpdateByFile struct {
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
File string `json:"file"`
}
type ChangeDBInfo struct {
ID uint `json:"id"`
From string `json:"from" validate:"required,oneof=local remote"`
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql"`
Database string `json:"database" validate:"required"`
Value string `json:"value" validate:"required"`
}
type DBBaseInfo struct {
Name string `json:"name"`
ContainerName string `json:"containerName"`
Port int64 `json:"port"`
}
// redis // redis
type ChangeRedisPass struct { type ChangeRedisPass struct {

View File

@ -43,6 +43,13 @@ type PostgresqlDBCreate struct {
Description string `json:"description"` Description string `json:"description"`
} }
type PostgresqlBindUser struct {
Name string `json:"name" validate:"required"`
Database string `json:"database" validate:"required"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
}
type PostgresqlLoadDB struct { type PostgresqlLoadDB struct {
From string `json:"from" validate:"required,oneof=local remote"` From string `json:"from" validate:"required,oneof=local remote"`
Type string `json:"type" validate:"required,oneof=postgresql"` Type string `json:"type" validate:"required,oneof=postgresql"`

View File

@ -0,0 +1,94 @@
package service
import (
"bufio"
"fmt"
"os"
"path"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"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/compose"
)
type DBCommonService struct{}
type IDBCommonService interface {
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
UpdateConfByFile(req dto.DBConfUpdateByFile) error
}
func NewIDBCommonService() IDBCommonService {
return &DBCommonService{}
}
func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
var data dto.DBBaseInfo
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
if err != nil {
return nil, err
}
data.ContainerName = app.ContainerName
data.Name = app.Name
data.Port = int64(app.Port)
return &data, nil
}
func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
filePath := ""
switch req.Type {
case "mysql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
case "mariadb-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/conf/my.cnf", req.Name))
case "postgresql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
case "redis-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "mysql-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
case "mariadb-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func (u *DBCommonService) UpdateConfByFile(req dto.DBConfUpdateByFile) error {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
if err != nil {
return err
}
path := ""
switch req.Type {
case constant.AppMariaDB, constant.AppMysql:
path = fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
case constant.AppPostgresql:
path = fmt.Sprintf("%s/%s/%s/data/postgresql.conf", constant.AppInstallDir, req.Type, app.Name)
case constant.AppRedis:
path = fmt.Sprintf("%s/%s/%s/conf/redis.conf", constant.AppInstallDir, req.Type, app.Name)
}
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
return err
}
return nil
}

View File

@ -1,7 +1,6 @@
package service package service
import ( import (
"bufio"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -40,17 +39,13 @@ type IMysqlService interface {
ChangeAccess(info dto.ChangeDBInfo) error ChangeAccess(info dto.ChangeDBInfo) error
ChangePassword(info dto.ChangeDBInfo) error ChangePassword(info dto.ChangeDBInfo) error
UpdateVariables(req dto.MysqlVariablesUpdate) error UpdateVariables(req dto.MysqlVariablesUpdate) error
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
UpdateDescription(req dto.UpdateDescription) error UpdateDescription(req dto.UpdateDescription) error
DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error) DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error)
Delete(ctx context.Context, req dto.MysqlDBDelete) error Delete(ctx context.Context, req dto.MysqlDBDelete) error
LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error)
LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error) LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error)
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error)
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
} }
func NewIMysqlService() IMysqlService { func NewIMysqlService() IMysqlService {
@ -406,26 +401,6 @@ func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
return nil return nil
} }
func (u *MysqlService) UpdateConfByFile(req dto.MysqlConfUpdateByFile) error {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
if err != nil {
return err
}
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
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 *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error { func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database) app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
if err != nil { if err != nil {
@ -471,19 +446,6 @@ func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
return nil return nil
} }
func (u *MysqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
var data dto.DBBaseInfo
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
if err != nil {
return nil, err
}
data.ContainerName = app.ContainerName
data.Name = app.Name
data.Port = int64(app.Port)
return &data, nil
}
func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) { func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name) app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
if err != nil { if err != nil {
@ -565,30 +527,6 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
return &info, nil return &info, nil
} }
func (u *MysqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
filePath := ""
switch req.Type {
case "mysql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
case "mariadb-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/conf/my.cnf", req.Name))
case "redis-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "mysql-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
case "mariadb-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func executeSqlForMaps(containerName, password, command string) (map[string]string, error) { func executeSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command) cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()

View File

@ -1,7 +1,6 @@
package service package service
import ( import (
"bufio"
"context" "context"
"fmt" "fmt"
"os" "os"
@ -14,7 +13,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd" "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt" "github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/postgresql" "github.com/1Panel-dev/1Panel/backend/utils/postgresql"
"github.com/1Panel-dev/1Panel/backend/utils/postgresql/client" "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
@ -28,16 +26,13 @@ type PostgresqlService struct{}
type IPostgresqlService interface { type IPostgresqlService interface {
SearchWithPage(search dto.PostgresqlDBSearch) (int64, interface{}, error) SearchWithPage(search dto.PostgresqlDBSearch) (int64, interface{}, error)
ListDBOption() ([]dto.PostgresqlOption, error) ListDBOption() ([]dto.PostgresqlOption, error)
BindUser(req dto.PostgresqlBindUser) error
Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error) Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error)
LoadFromRemote(req dto.PostgresqlLoadDB) error LoadFromRemote(database string) error
ChangePassword(info dto.ChangeDBInfo) error ChangePassword(info dto.ChangeDBInfo) error
UpdateConfByFile(info dto.PostgresqlConfUpdateByFile) error
UpdateDescription(req dto.UpdateDescription) error UpdateDescription(req dto.UpdateDescription) error
DeleteCheck(req dto.PostgresqlDBDeleteCheck) ([]string, error) DeleteCheck(req dto.PostgresqlDBDeleteCheck) ([]string, error)
Delete(ctx context.Context, req dto.PostgresqlDBDelete) error Delete(ctx context.Context, req dto.PostgresqlDBDelete) error
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
} }
func NewIPostgresqlService() IPostgresqlService { func NewIPostgresqlService() IPostgresqlService {
@ -88,6 +83,37 @@ func (u *PostgresqlService) ListDBOption() ([]dto.PostgresqlOption, error) {
return dbs, err return dbs, err
} }
func (u *PostgresqlService) BindUser(req dto.PostgresqlBindUser) error {
dbItem, err := postgresqlRepo.Get(postgresqlRepo.WithByPostgresqlName(req.Database), commonRepo.WithByName(req.Name))
if err != nil {
return err
}
pgClient, err := LoadPostgresqlClientByFrom(req.Database)
if err != nil {
return err
}
if err := pgClient.CreateUser(client.CreateInfo{
Name: req.Name,
Username: req.Username,
Password: req.Password,
Timeout: 300,
}, false); err != nil {
return err
}
pass, err := encrypt.StringEncrypt(req.Password)
if err != nil {
return fmt.Errorf("decrypt database db password failed, err: %v", err)
}
if err := postgresqlRepo.Update(dbItem.ID, map[string]interface{}{
"username": req.Username,
"password": pass,
}); err != nil {
return err
}
return nil
}
func (u *PostgresqlService) Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error) { func (u *PostgresqlService) Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error) {
if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format) { if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format) {
return nil, buserr.New(constant.ErrCmdIllegal) return nil, buserr.New(constant.ErrCmdIllegal)
@ -168,14 +194,14 @@ func LoadPostgresqlClientByFrom(database string) (postgresql.PostgresqlClient, e
return cli, nil return cli, nil
} }
func (u *PostgresqlService) LoadFromRemote(req dto.PostgresqlLoadDB) error { func (u *PostgresqlService) LoadFromRemote(database string) error {
client, err := LoadPostgresqlClientByFrom(req.Database) client, err := LoadPostgresqlClientByFrom(database)
if err != nil { if err != nil {
return err return err
} }
defer client.Close() defer client.Close()
databases, err := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(req.Database)) databases, err := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(database))
if err != nil { if err != nil {
return err return err
} }
@ -353,52 +379,3 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
} }
return nil return nil
} }
func (u *PostgresqlService) UpdateConfByFile(req dto.PostgresqlConfUpdateByFile) error {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
if err != nil {
return err
}
conf := fmt.Sprintf("%s/%s/%s/data/postgresql.conf", constant.AppInstallDir, req.Type, app.Name)
file, err := os.OpenFile(conf, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
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) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
var data dto.DBBaseInfo
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
if err != nil {
return nil, err
}
data.ContainerName = app.ContainerName
data.Name = app.Name
data.Port = int64(app.Port)
return &data, nil
}
func (u *PostgresqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
filePath := ""
switch req.Type {
case "postgresql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}

View File

@ -5,6 +5,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo" "github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/app/service" "github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/go-gormigrate/gormigrate/v2" "github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -133,14 +134,15 @@ var AddTableDatabasePostgresql = &gormigrate.Migration{
for _, job := range jobs { for _, job := range jobs {
var db model.DatabaseMysql var db model.DatabaseMysql
if err := tx.Where("id == ?", job.DBName).First(&db).Error; err != nil { if err := tx.Where("id == ?", job.DBName).First(&db).Error; err != nil {
return err continue
} }
var database model.Database var database model.Database
if err := tx.Where("name == ?", db.MysqlName).First(&database).Error; err != nil { if err := tx.Where("name == ?", db.MysqlName).First(&database).Error; err != nil {
return err continue
} }
if err := tx.Model(&model.Cronjob{}).Where("id = ?", job.ID).Update("db_type", database.Type).Error; err != nil { if err := tx.Model(&model.Cronjob{}).Where("id = ?", job.ID).Update("db_type", database.Type).Error; err != nil {
return err global.LOG.Errorf("update db type of cronjob %s failed, err: %v", job.Name, err)
continue
} }
} }
return nil return nil

View File

@ -16,6 +16,10 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) {
Use(middleware.PasswordExpired()) Use(middleware.PasswordExpired())
baseApi := v1.ApiGroupApp.BaseApi baseApi := v1.ApiGroupApp.BaseApi
{ {
cmdRouter.POST("/common/info", baseApi.LoadDBBaseInfo)
cmdRouter.POST("/common/load/file", baseApi.LoadDBFile)
cmdRouter.POST("/common/update/conf", baseApi.UpdateDBConfByFile)
cmdRouter.POST("", baseApi.CreateMysql) cmdRouter.POST("", baseApi.CreateMysql)
cmdRouter.POST("/bind", baseApi.BindUser) cmdRouter.POST("/bind", baseApi.BindUser)
cmdRouter.POST("load", baseApi.LoadDBFromRemote) cmdRouter.POST("load", baseApi.LoadDBFromRemote)
@ -25,12 +29,9 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/del", baseApi.DeleteMysql) cmdRouter.POST("/del", baseApi.DeleteMysql)
cmdRouter.POST("/description/update", baseApi.UpdateMysqlDescription) cmdRouter.POST("/description/update", baseApi.UpdateMysqlDescription)
cmdRouter.POST("/variables/update", baseApi.UpdateMysqlVariables) cmdRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
cmdRouter.POST("/conffile/update", baseApi.UpdateMysqlConfByFile)
cmdRouter.POST("/search", baseApi.SearchMysql) cmdRouter.POST("/search", baseApi.SearchMysql)
cmdRouter.POST("/load/file", baseApi.LoadDatabaseFile)
cmdRouter.POST("/variables", baseApi.LoadVariables) cmdRouter.POST("/variables", baseApi.LoadVariables)
cmdRouter.POST("/status", baseApi.LoadStatus) cmdRouter.POST("/status", baseApi.LoadStatus)
cmdRouter.POST("/baseinfo", baseApi.LoadBaseinfo)
cmdRouter.POST("/remote", baseApi.LoadRemoteAccess) cmdRouter.POST("/remote", baseApi.LoadRemoteAccess)
cmdRouter.GET("/options", baseApi.ListDBName) cmdRouter.GET("/options", baseApi.ListDBName)
@ -41,7 +42,6 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/redis/password", baseApi.ChangeRedisPassword) cmdRouter.POST("/redis/password", baseApi.ChangeRedisPassword)
cmdRouter.POST("/redis/backup/search", baseApi.RedisBackupList) cmdRouter.POST("/redis/backup/search", baseApi.RedisBackupList)
cmdRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf) cmdRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf)
cmdRouter.POST("/redis/conffile/update", baseApi.UpdateRedisConfByFile)
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf) cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
cmdRouter.POST("/db/check", baseApi.CheckDatabase) cmdRouter.POST("/db/check", baseApi.CheckDatabase)
@ -56,11 +56,11 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/pg", baseApi.CreatePostgresql) cmdRouter.POST("/pg", baseApi.CreatePostgresql)
cmdRouter.POST("/pg/search", baseApi.SearchPostgresql) cmdRouter.POST("/pg/search", baseApi.SearchPostgresql)
cmdRouter.POST("/pg/load", baseApi.LoadPostgresqlDBFromRemote) cmdRouter.POST("/pg/:database/load", baseApi.LoadPostgresqlDBFromRemote)
cmdRouter.POST("/pg/bind", baseApi.BindPostgresqlUser)
cmdRouter.POST("/pg/del/check", baseApi.DeleteCheckPostgresql) cmdRouter.POST("/pg/del/check", baseApi.DeleteCheckPostgresql)
cmdRouter.POST("/pg/del", baseApi.DeletePostgresql)
cmdRouter.POST("/pg/password", baseApi.ChangePostgresqlPassword) cmdRouter.POST("/pg/password", baseApi.ChangePostgresqlPassword)
cmdRouter.POST("/pg/description", baseApi.UpdatePostgresqlDescription) cmdRouter.POST("/pg/description", baseApi.UpdatePostgresqlDescription)
cmdRouter.POST("/pg/del", baseApi.DeletePostgresql)
cmdRouter.POST("/pg/conf", baseApi.UpdatePostgresqlConfByFile)
} }
} }

View File

@ -14,6 +14,7 @@ import (
type PostgresqlClient interface { type PostgresqlClient interface {
Create(info client.CreateInfo) error Create(info client.CreateInfo) error
CreateUser(info client.CreateInfo, withDeleteDB bool) error
Delete(info client.DeleteInfo) error Delete(info client.DeleteInfo) error
ChangePassword(info client.PasswordChangeInfo) error ChangePassword(info client.PasswordChangeInfo) error

View File

@ -3916,42 +3916,6 @@ const docTemplate = `{
} }
} }
}, },
"/databases/baseinfo": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 mysql 基础信息",
"consumes": [
"application/json"
],
"tags": [
"Database Mysql"
],
"summary": "Load mysql 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/bind": { "/databases/bind": {
"post": { "post": {
"security": [ "security": [
@ -4097,21 +4061,21 @@ const docTemplate = `{
} }
} }
}, },
"/databases/conffile/update": { "/databases/common/info": {
"post": { "post": {
"security": [ "security": [
{ {
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "上传替换 mysql 配置文件", "description": "获取数据库基础信息",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"tags": [ "tags": [
"Database Mysql" "Database Common"
], ],
"summary": "Update mysql conf by upload file", "summary": "Load base info",
"parameters": [ "parameters": [
{ {
"description": "request", "description": "request",
@ -4119,7 +4083,76 @@ const docTemplate = `{
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/dto.MysqlConfUpdateByFile" "$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.DBBaseInfo"
}
}
}
}
},
"/databases/common/load/file": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取数据库配置文件",
"consumes": [
"application/json"
],
"tags": [
"Database Common"
],
"summary": "Load Database conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/databases/common/update/conf": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "上传替换配置文件",
"consumes": [
"application/json"
],
"tags": [
"Database Common"
],
"summary": "Update conf by upload file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.DBConfUpdateByFile"
} }
} }
], ],
@ -4130,9 +4163,12 @@ const docTemplate = `{
}, },
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [], "BeforeFunctions": [],
"bodyKeys": [], "bodyKeys": [
"formatEN": "update the mysql database configuration information", "type",
"formatZH": "更新 mysql 数据库配置信息", "database"
],
"formatEN": "update the [type] [database] database configuration information",
"formatZH": "更新 [type] 数据库 [database] 配置信息",
"paramKeys": [] "paramKeys": []
} }
} }
@ -4595,39 +4631,6 @@ const docTemplate = `{
"responses": {} "responses": {}
} }
}, },
"/databases/load/file": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取数据库文件",
"consumes": [
"application/json"
],
"tags": [
"Database"
],
"summary": "Load Database file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/databases/options": { "/databases/options": {
"get": { "get": {
"security": [ "security": [
@ -4709,21 +4712,21 @@ const docTemplate = `{
} }
} }
}, },
"/databases/pg/baseinfo": { "/databases/pg/:database/load": {
"post": { "post": {
"security": [ "security": [
{ {
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "获取 postgresql 基础信息", "description": "从服务器获取",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"tags": [ "tags": [
"Database Postgresql" "Database Postgresql"
], ],
"summary": "Load postgresql base info", "summary": "Load postgresql database from remote",
"parameters": [ "parameters": [
{ {
"description": "request", "description": "request",
@ -4731,35 +4734,28 @@ const docTemplate = `{
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType" "$ref": "#/definitions/dto.PostgresqlLoadDB"
} }
} }
], ],
"responses": { "responses": {}
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.DBBaseInfo"
}
}
}
} }
}, },
"/databases/pg/conf": { "/databases/pg/bind": {
"post": { "post": {
"security": [ "security": [
{ {
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "上传替换 postgresql 配置文件", "description": "绑定 postgresql 数据库用户",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"tags": [ "tags": [
"Database Postgresql" "Database Postgresql"
], ],
"summary": "Update postgresql conf by upload file", "summary": "Bind postgresql user",
"parameters": [ "parameters": [
{ {
"description": "request", "description": "request",
@ -4767,7 +4763,7 @@ const docTemplate = `{
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/dto.PostgresqlConfUpdateByFile" "$ref": "#/definitions/dto.PostgresqlBindUser"
} }
} }
], ],
@ -4778,9 +4774,12 @@ const docTemplate = `{
}, },
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [], "BeforeFunctions": [],
"bodyKeys": [], "bodyKeys": [
"formatEN": "update the postgresql database configuration information", "name",
"formatZH": "更新 postgresql 数据库配置信息", "username"
],
"formatEN": "bind postgresql database [name] user [username]",
"formatZH": "绑定 postgresql 数据库 [name] 用户 [username]",
"paramKeys": [] "paramKeys": []
} }
} }
@ -4927,35 +4926,6 @@ const docTemplate = `{
} }
} }
}, },
"/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": { "/databases/pg/options": {
"get": { "get": {
"security": [ "security": [
@ -5180,46 +5150,6 @@ const docTemplate = `{
} }
} }
}, },
"/databases/redis/conffile/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "上传更新 redis 配置信息",
"consumes": [
"application/json"
],
"tags": [
"Database Redis"
],
"summary": "Update redis conf by file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RedisConfUpdateByFile"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "update the redis database configuration information",
"formatZH": "更新 redis 数据库配置信息",
"paramKeys": []
}
}
},
"/databases/redis/password": { "/databases/redis/password": {
"post": { "post": {
"security": [ "security": [
@ -15084,6 +15014,30 @@ const docTemplate = `{
} }
} }
}, },
"dto.DBConfUpdateByFile": {
"type": "object",
"required": [
"database",
"type"
],
"properties": {
"database": {
"type": "string"
},
"file": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"mysql",
"mariadb",
"postgresql",
"redis"
]
}
}
},
"dto.DaemonJsonConf": { "dto.DaemonJsonConf": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -16289,28 +16243,6 @@ const docTemplate = `{
} }
} }
}, },
"dto.MysqlConfUpdateByFile": {
"type": "object",
"required": [
"database",
"type"
],
"properties": {
"database": {
"type": "string"
},
"file": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"mysql",
"mariadb"
]
}
}
},
"dto.MysqlDBCreate": { "dto.MysqlDBCreate": {
"type": "object", "type": "object",
"required": [ "required": [
@ -16992,25 +16924,26 @@ const docTemplate = `{
} }
} }
}, },
"dto.PostgresqlConfUpdateByFile": { "dto.PostgresqlBindUser": {
"type": "object", "type": "object",
"required": [ "required": [
"database", "database",
"type" "name",
"password",
"username"
], ],
"properties": { "properties": {
"database": { "database": {
"type": "string" "type": "string"
}, },
"file": { "name": {
"type": "string" "type": "string"
}, },
"type": { "password": {
"type": "string", "type": "string"
"enum": [ },
"postgresql", "username": {
"mariadb" "type": "string"
]
} }
} }
}, },
@ -17268,20 +17201,6 @@ const docTemplate = `{
} }
} }
}, },
"dto.RedisConfUpdateByFile": {
"type": "object",
"required": [
"file"
],
"properties": {
"file": {
"type": "string"
},
"restartNow": {
"type": "boolean"
}
}
},
"dto.RedisPersistence": { "dto.RedisPersistence": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -3909,42 +3909,6 @@
} }
} }
}, },
"/databases/baseinfo": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 mysql 基础信息",
"consumes": [
"application/json"
],
"tags": [
"Database Mysql"
],
"summary": "Load mysql 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/bind": { "/databases/bind": {
"post": { "post": {
"security": [ "security": [
@ -4090,21 +4054,21 @@
} }
} }
}, },
"/databases/conffile/update": { "/databases/common/info": {
"post": { "post": {
"security": [ "security": [
{ {
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "上传替换 mysql 配置文件", "description": "获取数据库基础信息",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"tags": [ "tags": [
"Database Mysql" "Database Common"
], ],
"summary": "Update mysql conf by upload file", "summary": "Load base info",
"parameters": [ "parameters": [
{ {
"description": "request", "description": "request",
@ -4112,7 +4076,76 @@
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/dto.MysqlConfUpdateByFile" "$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.DBBaseInfo"
}
}
}
}
},
"/databases/common/load/file": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取数据库配置文件",
"consumes": [
"application/json"
],
"tags": [
"Database Common"
],
"summary": "Load Database conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/databases/common/update/conf": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "上传替换配置文件",
"consumes": [
"application/json"
],
"tags": [
"Database Common"
],
"summary": "Update conf by upload file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.DBConfUpdateByFile"
} }
} }
], ],
@ -4123,9 +4156,12 @@
}, },
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [], "BeforeFunctions": [],
"bodyKeys": [], "bodyKeys": [
"formatEN": "update the mysql database configuration information", "type",
"formatZH": "更新 mysql 数据库配置信息", "database"
],
"formatEN": "update the [type] [database] database configuration information",
"formatZH": "更新 [type] 数据库 [database] 配置信息",
"paramKeys": [] "paramKeys": []
} }
} }
@ -4588,39 +4624,6 @@
"responses": {} "responses": {}
} }
}, },
"/databases/load/file": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取数据库文件",
"consumes": [
"application/json"
],
"tags": [
"Database"
],
"summary": "Load Database file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/databases/options": { "/databases/options": {
"get": { "get": {
"security": [ "security": [
@ -4702,21 +4705,21 @@
} }
} }
}, },
"/databases/pg/baseinfo": { "/databases/pg/:database/load": {
"post": { "post": {
"security": [ "security": [
{ {
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "获取 postgresql 基础信息", "description": "从服务器获取",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"tags": [ "tags": [
"Database Postgresql" "Database Postgresql"
], ],
"summary": "Load postgresql base info", "summary": "Load postgresql database from remote",
"parameters": [ "parameters": [
{ {
"description": "request", "description": "request",
@ -4724,35 +4727,28 @@
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType" "$ref": "#/definitions/dto.PostgresqlLoadDB"
} }
} }
], ],
"responses": { "responses": {}
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.DBBaseInfo"
}
}
}
} }
}, },
"/databases/pg/conf": { "/databases/pg/bind": {
"post": { "post": {
"security": [ "security": [
{ {
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "上传替换 postgresql 配置文件", "description": "绑定 postgresql 数据库用户",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"tags": [ "tags": [
"Database Postgresql" "Database Postgresql"
], ],
"summary": "Update postgresql conf by upload file", "summary": "Bind postgresql user",
"parameters": [ "parameters": [
{ {
"description": "request", "description": "request",
@ -4760,7 +4756,7 @@
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/dto.PostgresqlConfUpdateByFile" "$ref": "#/definitions/dto.PostgresqlBindUser"
} }
} }
], ],
@ -4771,9 +4767,12 @@
}, },
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [], "BeforeFunctions": [],
"bodyKeys": [], "bodyKeys": [
"formatEN": "update the postgresql database configuration information", "name",
"formatZH": "更新 postgresql 数据库配置信息", "username"
],
"formatEN": "bind postgresql database [name] user [username]",
"formatZH": "绑定 postgresql 数据库 [name] 用户 [username]",
"paramKeys": [] "paramKeys": []
} }
} }
@ -4920,35 +4919,6 @@
} }
} }
}, },
"/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": { "/databases/pg/options": {
"get": { "get": {
"security": [ "security": [
@ -5173,46 +5143,6 @@
} }
} }
}, },
"/databases/redis/conffile/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "上传更新 redis 配置信息",
"consumes": [
"application/json"
],
"tags": [
"Database Redis"
],
"summary": "Update redis conf by file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RedisConfUpdateByFile"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "update the redis database configuration information",
"formatZH": "更新 redis 数据库配置信息",
"paramKeys": []
}
}
},
"/databases/redis/password": { "/databases/redis/password": {
"post": { "post": {
"security": [ "security": [
@ -15077,6 +15007,30 @@
} }
} }
}, },
"dto.DBConfUpdateByFile": {
"type": "object",
"required": [
"database",
"type"
],
"properties": {
"database": {
"type": "string"
},
"file": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"mysql",
"mariadb",
"postgresql",
"redis"
]
}
}
},
"dto.DaemonJsonConf": { "dto.DaemonJsonConf": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -16282,28 +16236,6 @@
} }
} }
}, },
"dto.MysqlConfUpdateByFile": {
"type": "object",
"required": [
"database",
"type"
],
"properties": {
"database": {
"type": "string"
},
"file": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"mysql",
"mariadb"
]
}
}
},
"dto.MysqlDBCreate": { "dto.MysqlDBCreate": {
"type": "object", "type": "object",
"required": [ "required": [
@ -16985,25 +16917,26 @@
} }
} }
}, },
"dto.PostgresqlConfUpdateByFile": { "dto.PostgresqlBindUser": {
"type": "object", "type": "object",
"required": [ "required": [
"database", "database",
"type" "name",
"password",
"username"
], ],
"properties": { "properties": {
"database": { "database": {
"type": "string" "type": "string"
}, },
"file": { "name": {
"type": "string" "type": "string"
}, },
"type": { "password": {
"type": "string", "type": "string"
"enum": [ },
"postgresql", "username": {
"mariadb" "type": "string"
]
} }
} }
}, },
@ -17261,20 +17194,6 @@
} }
} }
}, },
"dto.RedisConfUpdateByFile": {
"type": "object",
"required": [
"file"
],
"properties": {
"file": {
"type": "string"
},
"restartNow": {
"type": "boolean"
}
}
},
"dto.RedisPersistence": { "dto.RedisPersistence": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -705,6 +705,23 @@ definitions:
port: port:
type: integer type: integer
type: object type: object
dto.DBConfUpdateByFile:
properties:
database:
type: string
file:
type: string
type:
enum:
- mysql
- mariadb
- postgresql
- redis
type: string
required:
- database
- type
type: object
dto.DaemonJsonConf: dto.DaemonJsonConf:
properties: properties:
cgroupDriver: cgroupDriver:
@ -1518,21 +1535,6 @@ definitions:
- interval - interval
- secret - secret
type: object type: object
dto.MysqlConfUpdateByFile:
properties:
database:
type: string
file:
type: string
type:
enum:
- mysql
- mariadb
type: string
required:
- database
- type
type: object
dto.MysqlDBCreate: dto.MysqlDBCreate:
properties: properties:
database: database:
@ -1998,20 +2000,21 @@ definitions:
required: required:
- serverPort - serverPort
type: object type: object
dto.PostgresqlConfUpdateByFile: dto.PostgresqlBindUser:
properties: properties:
database: database:
type: string type: string
file: name:
type: string type: string
type: password:
enum: type: string
- postgresql username:
- mariadb
type: string type: string
required: required:
- database - database
- type - name
- password
- username
type: object type: object
dto.PostgresqlDBCreate: dto.PostgresqlDBCreate:
properties: properties:
@ -2185,15 +2188,6 @@ definitions:
timeout: timeout:
type: string type: string
type: object type: object
dto.RedisConfUpdateByFile:
properties:
file:
type: string
restartNow:
type: boolean
required:
- file
type: object
dto.RedisPersistence: dto.RedisPersistence:
properties: properties:
appendfsync: appendfsync:
@ -7466,28 +7460,6 @@ paths:
formatEN: create mysql database [name] formatEN: create mysql database [name]
formatZH: 创建 mysql 数据库 [name] formatZH: 创建 mysql 数据库 [name]
paramKeys: [] paramKeys: []
/databases/baseinfo:
post:
consumes:
- application/json
description: 获取 mysql 基础信息
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 mysql base info
tags:
- Database Mysql
/databases/bind: /databases/bind:
post: post:
consumes: consumes:
@ -7582,31 +7554,75 @@ paths:
formatEN: Update database [name] password formatEN: Update database [name] password
formatZH: 更新数据库 [name] 密码 formatZH: 更新数据库 [name] 密码
paramKeys: [] paramKeys: []
/databases/conffile/update: /databases/common/info:
post: post:
consumes: consumes:
- application/json - application/json
description: 上传替换 mysql 配置文件 description: 获取数据库基础信息
parameters: parameters:
- description: request - description: request
in: body in: body
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/dto.MysqlConfUpdateByFile' $ref: '#/definitions/dto.OperationWithNameAndType'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/dto.DBBaseInfo'
security:
- ApiKeyAuth: []
summary: Load base info
tags:
- Database Common
/databases/common/load/file:
post:
consumes:
- application/json
description: 获取数据库配置文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OperationWithNameAndType'
responses: responses:
"200": "200":
description: OK description: OK
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
summary: Update mysql conf by upload file summary: Load Database conf
tags: tags:
- Database Mysql - Database Common
/databases/common/update/conf:
post:
consumes:
- application/json
description: 上传替换配置文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.DBConfUpdateByFile'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update conf by upload file
tags:
- Database Common
x-panel-log: x-panel-log:
BeforeFunctions: [] BeforeFunctions: []
bodyKeys: [] bodyKeys:
formatEN: update the mysql database configuration information - type
formatZH: 更新 mysql 数据库配置信息 - database
formatEN: update the [type] [database] database configuration information
formatZH: 更新 [type] 数据库 [database] 配置信息
paramKeys: [] paramKeys: []
/databases/db: /databases/db:
post: post:
@ -7898,26 +7914,6 @@ paths:
summary: Load mysql database from remote summary: Load mysql database from remote
tags: tags:
- Database Mysql - Database Mysql
/databases/load/file:
post:
consumes:
- application/json
description: 获取数据库文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OperationWithNameAndType'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load Database file
tags:
- Database
/databases/options: /databases/options:
get: get:
consumes: consumes:
@ -7969,53 +7965,51 @@ paths:
formatEN: create postgresql database [name] formatEN: create postgresql database [name]
formatZH: 创建 postgresql 数据库 [name] formatZH: 创建 postgresql 数据库 [name]
paramKeys: [] paramKeys: []
/databases/pg/baseinfo: /databases/pg/:database/load:
post: post:
consumes: consumes:
- application/json - application/json
description: 获取 postgresql 基础信息 description: 从服务器获取
parameters: parameters:
- description: request - description: request
in: body in: body
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/dto.OperationWithNameAndType' $ref: '#/definitions/dto.PostgresqlLoadDB'
responses: responses: {}
"200":
description: OK
schema:
$ref: '#/definitions/dto.DBBaseInfo'
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
summary: Load postgresql base info summary: Load postgresql database from remote
tags: tags:
- Database Postgresql - Database Postgresql
/databases/pg/conf: /databases/pg/bind:
post: post:
consumes: consumes:
- application/json - application/json
description: 上传替换 postgresql 配置文件 description: 绑定 postgresql 数据库用户
parameters: parameters:
- description: request - description: request
in: body in: body
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/dto.PostgresqlConfUpdateByFile' $ref: '#/definitions/dto.PostgresqlBindUser'
responses: responses:
"200": "200":
description: OK description: OK
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
summary: Update postgresql conf by upload file summary: Bind postgresql user
tags: tags:
- Database Postgresql - Database Postgresql
x-panel-log: x-panel-log:
BeforeFunctions: [] BeforeFunctions: []
bodyKeys: [] bodyKeys:
formatEN: update the postgresql database configuration information - name
formatZH: 更新 postgresql 数据库配置信息 - username
formatEN: bind postgresql database [name] user [username]
formatZH: 绑定 postgresql 数据库 [name] 用户 [username]
paramKeys: [] paramKeys: []
/databases/pg/del: /databases/pg/del:
post: post:
@ -8109,24 +8103,6 @@ paths:
[description] [description]
formatZH: postgresql 数据库 [name] 描述信息修改 [description] formatZH: postgresql 数据库 [name] 描述信息修改 [description]
paramKeys: [] 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: /databases/pg/options:
get: get:
consumes: consumes:
@ -8267,32 +8243,6 @@ paths:
formatEN: update the redis database configuration information formatEN: update the redis database configuration information
formatZH: 更新 redis 数据库配置信息 formatZH: 更新 redis 数据库配置信息
paramKeys: [] paramKeys: []
/databases/redis/conffile/update:
post:
consumes:
- application/json
description: 上传更新 redis 配置信息
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.RedisConfUpdateByFile'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update redis conf by file
tags:
- Database Redis
x-panel-log:
BeforeFunctions: []
bodyKeys: []
formatEN: update the redis database configuration information
formatZH: 更新 redis 数据库配置信息
paramKeys: []
/databases/redis/password: /databases/redis/password:
post: post:
consumes: consumes:

View File

@ -33,7 +33,7 @@ export namespace Database {
mysqlKey: string; mysqlKey: string;
containerName: string; containerName: string;
} }
export interface MysqlConfUpdateByFile { export interface DBConfUpdate {
type: string; type: string;
database: string; database: string;
file: string; file: string;
@ -146,10 +146,11 @@ export namespace Database {
type: string; type: string;
database: string; database: string;
} }
export interface PgLoadDB { export interface PgBind {
from: string; name: string;
type: string;
database: string; database: string;
username: string;
password: string;
} }
export interface PostgresqlDBDelete { export interface PostgresqlDBDelete {
id: number; id: number;

View File

@ -5,22 +5,27 @@ import { ResPage, DescriptionUpdate } from '../interface';
import { Database } from '../interface/database'; import { Database } from '../interface/database';
import { TimeoutEnum } from '@/enums/http-enum'; import { TimeoutEnum } from '@/enums/http-enum';
export const searchMysqlDBs = (params: Database.SearchDBWithPage) => { // common
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search`, params); export const loadDBBaseInfo = (type: string, database: string) => {
return http.post<Database.BaseInfo>(`/databases/common/info`, { type: type, name: database });
};
export const loadDBFile = (type: string, database: string) => {
return http.post<string>(`/databases/common/load/file`, { type: type, name: database });
};
export const updateDBFile = (params: Database.DBConfUpdate) => {
return http.post(`/databases/common/update/conf`, params);
}; };
export const loadDatabaseFile = (type: string, database: string) => { // pg
return http.post<string>(`/databases/load/file`, { type: type, name: database });
};
export const addPostgresqlDB = (params: Database.PostgresqlDBCreate) => { export const addPostgresqlDB = (params: Database.PostgresqlDBCreate) => {
let request = deepCopy(params) as Database.PostgresqlDBCreate; let request = deepCopy(params) as Database.PostgresqlDBCreate;
if (request.password) { if (request.password) {
request.password = Base64.encode(request.password); request.password = Base64.encode(request.password);
} }
return http.post(`/databases/pg`, request); return http.post(`/databases/pg`, request, TimeoutEnum.T_40S);
}; };
export const updatePostgresqlConfByFile = (params: Database.PostgresqlConfUpdateByFile) => { export const bindPostgresqlUser = (params: Database.PgBind) => {
return http.post(`/databases/pg/conf`, params); return http.post(`/databases/pg/bind`, params, TimeoutEnum.T_40S);
}; };
export const searchPostgresqlDBs = (params: Database.SearchDBWithPage) => { export const searchPostgresqlDBs = (params: Database.SearchDBWithPage) => {
return http.post<ResPage<Database.PostgresqlDBInfo>>(`/databases/pg/search`, params); return http.post<ResPage<Database.PostgresqlDBInfo>>(`/databases/pg/search`, params);
@ -28,24 +33,27 @@ export const searchPostgresqlDBs = (params: Database.SearchDBWithPage) => {
export const updatePostgresqlDescription = (params: DescriptionUpdate) => { export const updatePostgresqlDescription = (params: DescriptionUpdate) => {
return http.post(`/databases/pg/description`, params); return http.post(`/databases/pg/description`, params);
}; };
export const loadPgFromRemote = (params: Database.PgLoadDB) => { export const loadPgFromRemote = (database: string) => {
return http.post(`/databases/pg/load`, params); return http.post(`/databases/pg/${database}/load`);
}; };
export const deleteCheckPostgresqlDB = (params: Database.PostgresqlDBDeleteCheck) => { export const deleteCheckPostgresqlDB = (params: Database.PostgresqlDBDeleteCheck) => {
return http.post<Array<string>>(`/databases/pg/del/check`, params); return http.post<Array<string>>(`/databases/pg/del/check`, params, TimeoutEnum.T_40S);
}; };
export const updatePostgresqlPassword = (params: Database.ChangeInfo) => { export const updatePostgresqlPassword = (params: Database.ChangeInfo) => {
let request = deepCopy(params) as Database.ChangeInfo; let request = deepCopy(params) as Database.ChangeInfo;
if (request.value) { if (request.value) {
request.value = Base64.encode(request.value); request.value = Base64.encode(request.value);
} }
return http.post(`/databases/pg/password`, request); return http.post(`/databases/pg/password`, request, TimeoutEnum.T_40S);
}; };
export const deletePostgresqlDB = (params: Database.PostgresqlDBDelete) => { export const deletePostgresqlDB = (params: Database.PostgresqlDBDelete) => {
return http.post(`/databases/pg/del`, params); return http.post(`/databases/pg/del`, params, TimeoutEnum.T_40S);
}; };
// mysql // mysql
export const searchMysqlDBs = (params: Database.SearchDBWithPage) => {
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search`, params);
};
export const addMysqlDB = (params: Database.MysqlDBCreate) => { export const addMysqlDB = (params: Database.MysqlDBCreate) => {
let request = deepCopy(params) as Database.MysqlDBCreate; let request = deepCopy(params) as Database.MysqlDBCreate;
if (request.password) { if (request.password) {
@ -79,9 +87,6 @@ export const updateMysqlDescription = (params: DescriptionUpdate) => {
export const updateMysqlVariables = (params: Database.VariablesUpdate) => { export const updateMysqlVariables = (params: Database.VariablesUpdate) => {
return http.post(`/databases/variables/update`, params); return http.post(`/databases/variables/update`, params);
}; };
export const updateMysqlConfByFile = (params: Database.MysqlConfUpdateByFile) => {
return http.post(`/databases/conffile/update`, params);
};
export const deleteCheckMysqlDB = (params: Database.MysqlDBDeleteCheck) => { export const deleteCheckMysqlDB = (params: Database.MysqlDBDeleteCheck) => {
return http.post<Array<string>>(`/databases/del/check`, params); return http.post<Array<string>>(`/databases/del/check`, params);
}; };
@ -89,9 +94,6 @@ export const deleteMysqlDB = (params: Database.MysqlDBDelete) => {
return http.post(`/databases/del`, params); return http.post(`/databases/del`, params);
}; };
export const loadMysqlBaseInfo = (type: string, database: string) => {
return http.post<Database.BaseInfo>(`/databases/baseinfo`, { type: type, name: database });
};
export const loadMysqlVariables = (type: string, database: string) => { export const loadMysqlVariables = (type: string, database: string) => {
return http.post<Database.MysqlVariables>(`/databases/variables`, { type: type, name: database }); return http.post<Database.MysqlVariables>(`/databases/variables`, { type: type, name: database });
}; };

View File

@ -383,6 +383,7 @@ const message = {
loadFromRemote: 'Load from server', loadFromRemote: 'Load from server',
userBind: 'Bind User', userBind: 'Bind User',
pgBind: 'Bind User (Binding existing users is not currently supported)',
loadFromRemoteHelper: loadFromRemoteHelper:
'This action will synchronize the database info on the server to 1Panel, do you want to continue?', 'This action will synchronize the database info on the server to 1Panel, do you want to continue?',
passwordHelper: 'Unable to retrieve, please modify', passwordHelper: 'Unable to retrieve, please modify',

View File

@ -376,6 +376,7 @@ const message = {
loadFromRemote: '從服務器獲取', loadFromRemote: '從服務器獲取',
userBind: '綁定使用者', userBind: '綁定使用者',
pgBind: '綁定用戶(暫不支持綁定已有用戶)',
loadFromRemoteHelper: '此操作將同步服務器上數據庫信息到 1Panel是否繼續', loadFromRemoteHelper: '此操作將同步服務器上數據庫信息到 1Panel是否繼續',
passwordHelper: '無法獲取密碼請修改', passwordHelper: '無法獲取密碼請修改',
local: '本地', local: '本地',

View File

@ -376,6 +376,7 @@ const message = {
loadFromRemote: '从服务器获取', loadFromRemote: '从服务器获取',
userBind: '绑定用户', userBind: '绑定用户',
pgBind: '绑定用户(暂不支持绑定已有用户)',
loadFromRemoteHelper: '此操作将同步服务器上数据库信息到 1Panel是否继续', loadFromRemoteHelper: '此操作将同步服务器上数据库信息到 1Panel是否继续',
passwordHelper: '无法获取密码请修改', passwordHelper: '无法获取密码请修改',
local: '本地', local: '本地',

View File

@ -66,6 +66,7 @@ const bindVisible = ref(false);
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
const changeFormRef = ref<FormInstance>(); const changeFormRef = ref<FormInstance>();
const form = reactive({ const form = reactive({
from: '',
database: '', database: '',
mysqlName: '', mysqlName: '',
username: '', username: '',
@ -93,13 +94,14 @@ function checkIPs(rule: any, value: any, callback: any) {
} }
interface DialogProps { interface DialogProps {
from: string;
database: string; database: string;
mysqlName: string; mysqlName: string;
} }
const acceptParams = (params: DialogProps): void => { const acceptParams = (params: DialogProps): void => {
form.id = params.id;
form.database = params.database; form.database = params.database;
form.mysqlName = params.mysqlName; form.mysqlName = params.mysqlName;
form.from = params.from;
bindVisible.value = true; bindVisible.value = true;
}; };
const emit = defineEmits<{ (e: 'search'): void }>(); const emit = defineEmits<{ (e: 'search'): void }>();

View File

@ -529,6 +529,7 @@ const onBind = async (row: Database.MysqlDBInfo) => {
let param = { let param = {
database: currentDBName.value, database: currentDBName.value,
mysqlName: row.name, mysqlName: row.name,
from: row.from,
}; };
bindRef.value.acceptParams(param); bindRef.value.acceptParams(param);
}; };

View File

@ -147,7 +147,7 @@ import { onMounted, reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror'; import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript'; import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark'; import { oneDark } from '@codemirror/theme-one-dark';
import { loadDatabaseFile, loadMysqlBaseInfo, loadMysqlVariables, updateMysqlConfByFile } from '@/api/modules/database'; import { loadDBFile, loadDBBaseInfo, loadMysqlVariables, updateDBFile } from '@/api/modules/database';
import { ChangePort, CheckAppInstalled, GetAppDefaultConfig } from '@/api/modules/app'; import { ChangePort, CheckAppInstalled, GetAppDefaultConfig } from '@/api/modules/app';
import { Rules } from '@/global/form-rules'; import { Rules } from '@/global/form-rules';
import i18n from '@/lang'; import i18n from '@/lang';
@ -260,7 +260,7 @@ const onSubmitChangeConf = async () => {
file: mysqlConf.value, file: mysqlConf.value,
}; };
loading.value = true; loading.value = true;
await updateMysqlConfByFile(param) await updateDBFile(param)
.then(() => { .then(() => {
useOld.value = false; useOld.value = false;
loading.value = false; loading.value = false;
@ -286,7 +286,7 @@ const loadContainerLog = async (containerID: string) => {
}; };
const loadBaseInfo = async () => { const loadBaseInfo = async () => {
const res = await loadMysqlBaseInfo(props.type, props.database); const res = await loadDBBaseInfo(props.type, props.database);
mysqlName.value = res.data?.name; mysqlName.value = res.data?.name;
baseInfo.port = res.data?.port; baseInfo.port = res.data?.port;
baseInfo.containerID = res.data?.containerName; baseInfo.containerID = res.data?.containerName;
@ -323,7 +323,7 @@ const loadSlowLogs = async () => {
const loadMysqlConf = async () => { const loadMysqlConf = async () => {
useOld.value = false; useOld.value = false;
await loadDatabaseFile(props.type + '-conf', props.database) await loadDBFile(props.type + '-conf', props.database)
.then((res) => { .then((res) => {
loading.value = false; loading.value = false;
mysqlConf.value = res.data; mysqlConf.value = res.data;

View File

@ -52,7 +52,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue'; import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import { Database } from '@/api/interface/database'; import { Database } from '@/api/interface/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { loadDatabaseFile, updateMysqlVariables } from '@/api/modules/database'; import { loadDBFile, updateMysqlVariables } from '@/api/modules/database';
import { dateFormatForName, downloadWithContent } from '@/utils/util'; import { dateFormatForName, downloadWithContent } from '@/utils/util';
import i18n from '@/lang'; import i18n from '@/lang';
import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message'; import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message';
@ -175,7 +175,7 @@ const onDownload = async () => {
}; };
const loadMysqlSlowlogs = async () => { const loadMysqlSlowlogs = async () => {
const res = await loadDatabaseFile(currentDB.type + '-slow-logs', currentDB.database); const res = await loadDBFile(currentDB.type + '-slow-logs', currentDB.database);
slowLogs.value = res.data || ''; slowLogs.value = res.data || '';
nextTick(() => { nextTick(() => {
const state = view.value.state; const state = view.value.state;

View File

@ -0,0 +1,103 @@
<template>
<div>
<el-drawer v-model="bindVisible" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
<template #header>
<DrawerHeader :header="$t('database.userBind')" :resource="form.name" :back="handleClose" />
</template>
<el-form v-loading="loading" ref="changeFormRef" :model="form" :rules="rules" label-position="top">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-alert type="warning" :description="$t('database.pgBindHelper')" :closable="false" />
<el-form-item class="mt-5" :label="$t('commons.login.username')" prop="username">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item :label="$t('commons.login.password')" prop="password">
<el-input type="password" clearable show-password v-model="form.password" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button :disabled="loading" @click="bindVisible = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" type="primary" @click="onSubmit(changeFormRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { bindPostgresqlUser } from '@/api/modules/database';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { Rules } from '@/global/form-rules';
import { MsgSuccess } from '@/utils/message';
const loading = ref();
const bindVisible = ref(false);
type FormInstance = InstanceType<typeof ElForm>;
const changeFormRef = ref<FormInstance>();
const form = reactive({
database: '',
name: '',
username: '',
password: '',
});
const confirmDialogRef = ref();
const rules = reactive({
username: [Rules.requiredInput, Rules.name],
password: [Rules.paramComplexity],
});
interface DialogProps {
database: string;
name: string;
}
const acceptParams = (params: DialogProps): void => {
form.database = params.database;
form.name = params.name;
bindVisible.value = true;
};
const emit = defineEmits<{ (e: 'search'): void }>();
const handleClose = () => {
bindVisible.value = false;
};
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let param = {
name: form.name,
database: form.database,
username: form.username,
password: form.password,
};
loading.value = true;
await bindPostgresqlUser(param)
.then(() => {
loading.value = false;
emit('search');
bindVisible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
});
};
defineExpose({
acceptParams,
});
</script>

View File

@ -101,10 +101,24 @@
<template #main v-if="currentDB"> <template #main v-if="currentDB">
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data"> <ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
<el-table-column :label="$t('commons.table.name')" prop="name" sortable /> <el-table-column :label="$t('commons.table.name')" prop="name" sortable />
<el-table-column :label="$t('commons.login.username')" prop="username" /> <el-table-column :label="$t('commons.login.username')" prop="username">
<template #default="{ row }">
<div class="flex items-center" v-if="row.username">
<span>
{{ row.username }}
</span>
</div>
<div v-else>
<el-button style="margin-left: -3px" type="primary" link @click="onBind(row)">
{{ $t('database.userBind') }}
</el-button>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('commons.login.password')" prop="password"> <el-table-column :label="$t('commons.login.password')" prop="password">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center" v-if="row.password"> <span v-if="row.username === '' || row.password === ''">-</span>
<div class="flex items-center" v-else>
<div class="star-center" v-if="!row.showPassword"> <div class="star-center" v-if="!row.showPassword">
<span>**********</span> <span>**********</span>
</div> </div>
@ -131,11 +145,6 @@
<CopyButton :content="row.password" type="icon" /> <CopyButton :content="row.password" type="icon" />
</div> </div>
</div> </div>
<div v-else>
<el-link @click="onChangePassword(row)">
<span style="font-size: 12px">{{ $t('database.passwordHelper') }}</span>
</el-link>
</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.description')" prop="description"> <el-table-column :label="$t('commons.table.description')" prop="description">
@ -198,6 +207,7 @@
</template> </template>
</el-dialog> </el-dialog>
<BindDialog ref="bindRef" @search="search" />
<PasswordDialog ref="passwordRef" @search="search" /> <PasswordDialog ref="passwordRef" @search="search" />
<RootPasswordDialog ref="connRef" /> <RootPasswordDialog ref="connRef" />
<UploadDialog ref="uploadRef" /> <UploadDialog ref="uploadRef" />
@ -212,6 +222,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import BindDialog from '@/views/database/postgresql/bind/index.vue';
import OperateDialog from '@/views/database/postgresql/create/index.vue'; import OperateDialog from '@/views/database/postgresql/create/index.vue';
import DeleteDialog from '@/views/database/postgresql/delete/index.vue'; import DeleteDialog from '@/views/database/postgresql/delete/index.vue';
import PasswordDialog from '@/views/database/postgresql/password/index.vue'; import PasswordDialog from '@/views/database/postgresql/password/index.vue';
@ -252,6 +263,7 @@ const currentDBName = ref();
const checkRef = ref(); const checkRef = ref();
const deleteRef = ref(); const deleteRef = ref();
const bindRef = ref();
const pgadminPort = ref(); const pgadminPort = ref();
const dashboardName = ref(); const dashboardName = ref();
@ -352,6 +364,14 @@ const search = async (column?: any) => {
paginationConfig.total = res.data.total; paginationConfig.total = res.data.total;
}; };
const onBind = async (row: Database.PostgresqlDBInfo) => {
let param = {
name: row.name,
database: currentDBName.value,
};
bindRef.value.acceptParams(param);
};
const loadDB = async () => { const loadDB = async () => {
ElMessageBox.confirm(i18n.global.t('database.loadFromRemoteHelper'), i18n.global.t('commons.msg.infoTitle'), { ElMessageBox.confirm(i18n.global.t('database.loadFromRemoteHelper'), i18n.global.t('commons.msg.infoTitle'), {
confirmButtonText: i18n.global.t('commons.button.confirm'), confirmButtonText: i18n.global.t('commons.button.confirm'),
@ -359,12 +379,7 @@ const loadDB = async () => {
type: 'info', type: 'info',
}).then(async () => { }).then(async () => {
loading.value = true; loading.value = true;
let params = { await loadPgFromRemote(currentDBName.value)
from: currentDB.value.from,
type: currentDB.value.type,
database: currentDBName.value,
};
await loadPgFromRemote(params)
.then(() => { .then(() => {
loading.value = false; loading.value = false;
search(); search();

View File

@ -98,7 +98,7 @@ import { onMounted, reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror'; import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript'; import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark'; import { oneDark } from '@codemirror/theme-one-dark';
import { loadDatabaseFile, loadMysqlBaseInfo, updatePostgresqlConfByFile } from '@/api/modules/database'; import { loadDBFile, loadDBBaseInfo, updateDBFile } from '@/api/modules/database';
import { ChangePort, CheckAppInstalled } from '@/api/modules/app'; import { ChangePort, CheckAppInstalled } from '@/api/modules/app';
import { Rules } from '@/global/form-rules'; import { Rules } from '@/global/form-rules';
import i18n from '@/lang'; import i18n from '@/lang';
@ -186,7 +186,7 @@ const onSubmitChangeConf = async () => {
file: postgresqlConf.value, file: postgresqlConf.value,
}; };
loading.value = true; loading.value = true;
await updatePostgresqlConfByFile(param) await updateDBFile(param)
.then(() => { .then(() => {
loading.value = false; loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
@ -211,7 +211,7 @@ const loadContainerLog = async (containerID: string) => {
}; };
const loadBaseInfo = async () => { const loadBaseInfo = async () => {
const res = await loadMysqlBaseInfo(props.type, props.database); const res = await loadDBBaseInfo(props.type, props.database);
postgresqlName.value = res.data?.name; postgresqlName.value = res.data?.name;
baseInfo.port = res.data?.port; baseInfo.port = res.data?.port;
baseInfo.containerID = res.data?.containerName; baseInfo.containerID = res.data?.containerName;
@ -220,7 +220,7 @@ const loadBaseInfo = async () => {
}; };
const loadPostgresqlConf = async () => { const loadPostgresqlConf = async () => {
await loadDatabaseFile(props.type + '-conf', props.database) await loadDBFile(props.type + '-conf', props.database)
.then((res) => { .then((res) => {
loading.value = false; loading.value = false;
postgresqlConf.value = res.data; postgresqlConf.value = res.data;

View File

@ -135,7 +135,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import Status from '@/views/database/redis/setting/status/index.vue'; import Status from '@/views/database/redis/setting/status/index.vue';
import Persistence from '@/views/database/redis/setting/persistence/index.vue'; import Persistence from '@/views/database/redis/setting/persistence/index.vue';
import { loadDatabaseFile, loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/modules/database'; import { loadDBFile, loadRedisConf, updateRedisConf, updateDBFile } from '@/api/modules/database';
import i18n from '@/lang'; import i18n from '@/lang';
import { checkNumberRange, Rules } from '@/global/form-rules'; import { checkNumberRange, Rules } from '@/global/form-rules';
import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app'; import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app';
@ -313,11 +313,12 @@ const onSaveFile = async () => {
}; };
const submtiFile = async () => { const submtiFile = async () => {
let param = { let param = {
type: 'redis',
database: '',
file: redisConf.value, file: redisConf.value,
restartNow: true,
}; };
loading.value = true; loading.value = true;
await updateRedisConfByFile(param) await updateDBFile(param)
.then(() => { .then(() => {
useOld.value = false; useOld.value = false;
loading.value = false; loading.value = false;
@ -340,7 +341,7 @@ const loadform = async () => {
const loadConfFile = async () => { const loadConfFile = async () => {
useOld.value = false; useOld.value = false;
loading.value = true; loading.value = true;
await loadDatabaseFile('redis-conf', redisName.value) await loadDBFile('redis-conf', redisName.value)
.then((res) => { .then((res) => {
loading.value = false; loading.value = false;
redisConf.value = res.data; redisConf.value = res.data;

4
go.mod
View File

@ -29,7 +29,6 @@ require (
github.com/jinzhu/gorm v1.9.2 github.com/jinzhu/gorm v1.9.2
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/klauspost/compress v1.16.5 github.com/klauspost/compress v1.16.5
github.com/mattn/go-sqlite3 v1.14.19
github.com/mholt/archiver/v4 v4.0.0-alpha.8 github.com/mholt/archiver/v4 v4.0.0-alpha.8
github.com/minio/minio-go/v7 v7.0.36 github.com/minio/minio-go/v7 v7.0.36
github.com/mojocn/base64Captcha v1.3.6 github.com/mojocn/base64Captcha v1.3.6
@ -61,7 +60,6 @@ require (
gopkg.in/ini.v1 v1.67.0 gopkg.in/ini.v1 v1.67.0
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/sqlite v1.5.4
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55
) )
@ -160,6 +158,7 @@ require (
github.com/mailru/easyjson v0.7.6 // indirect github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mattn/go-sqlite3 v1.14.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.55 // indirect github.com/miekg/dns v1.1.55 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect
@ -240,6 +239,7 @@ require (
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/sqlite v1.5.4 // indirect
k8s.io/api v0.26.3 // indirect k8s.io/api v0.26.3 // indirect
k8s.io/apimachinery v0.26.3 // indirect k8s.io/apimachinery v0.26.3 // indirect
k8s.io/client-go v0.26.2 // indirect k8s.io/client-go v0.26.2 // indirect