mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 22:18:07 +08:00
feat: 数据库实现远程服务器获取功能 (#1775)
This commit is contained in:
parent
e83e592e0a
commit
40aaa1ceb0
@ -229,6 +229,25 @@ func (b *BaseApi) ListDBName(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, list)
|
helper.SuccessWithData(c, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Database Mysql
|
||||||
|
// @Summary Load mysql database from remote
|
||||||
|
// @Description 从服务器获取
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /databases/load/:from [get]
|
||||||
|
func (b *BaseApi) LoadDBFromRemote(c *gin.Context) {
|
||||||
|
from, err := helper.GetStrParamByKey(c, "from")
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := mysqlService.LoadFromRemote(from); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Database Mysql
|
// @Tags Database Mysql
|
||||||
// @Summary Check before delete mysql database
|
// @Summary Check before delete mysql database
|
||||||
// @Description Mysql 数据库删除前检查
|
// @Description Mysql 数据库删除前检查
|
||||||
|
@ -63,7 +63,7 @@ func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Database
|
// @Tags Database
|
||||||
// @Summary List remote databases
|
// @Summary List remote databases
|
||||||
// @Description 获取快速命令列表
|
// @Description 获取远程数据库列表
|
||||||
// @Success 200 {array} dto.RemoteDBOption
|
// @Success 200 {array} dto.RemoteDBOption
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /databases/remote/list/:type [get]
|
// @Router /databases/remote/list/:type [get]
|
||||||
@ -82,6 +82,27 @@ func (b *BaseApi) ListRemoteDB(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, list)
|
helper.SuccessWithData(c, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Database
|
||||||
|
// @Summary Get remote databases
|
||||||
|
// @Description 获取远程数据库
|
||||||
|
// @Success 200 dto.RemoteDBOption
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /databases/remote/:name [get]
|
||||||
|
func (b *BaseApi) GetRemoteDB(c *gin.Context) {
|
||||||
|
name, err := helper.GetStrParamByKey(c, "name")
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := remoteDBService.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Database
|
// @Tags Database
|
||||||
// @Summary Delete remote database
|
// @Summary Delete remote database
|
||||||
// @Description 删除远程数据库
|
// @Description 删除远程数据库
|
||||||
|
@ -3,7 +3,7 @@ package model
|
|||||||
type DatabaseMysql struct {
|
type DatabaseMysql struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name" gorm:"type:varchar(256);not null"`
|
Name string `json:"name" gorm:"type:varchar(256);not null"`
|
||||||
From string `json:"type" gorm:"type:varchar(256);not null;default:'local'"`
|
From string `json:"from" gorm:"type:varchar(256);not null;default:local"`
|
||||||
MysqlName string `json:"mysqlName" gorm:"type:varchar(64);not null"`
|
MysqlName string `json:"mysqlName" gorm:"type:varchar(64);not null"`
|
||||||
Format string `json:"format" gorm:"type:varchar(64);not null"`
|
Format string `json:"format" gorm:"type:varchar(64);not null"`
|
||||||
Username string `json:"username" gorm:"type:varchar(256);not null"`
|
Username string `json:"username" gorm:"type:varchar(256);not null"`
|
||||||
|
@ -33,6 +33,7 @@ type IMysqlService interface {
|
|||||||
SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error)
|
SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error)
|
||||||
ListDBName() ([]string, error)
|
ListDBName() ([]string, error)
|
||||||
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
|
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
|
||||||
|
LoadFromRemote(from string) error
|
||||||
ChangeAccess(info dto.ChangeDBInfo) error
|
ChangeAccess(info dto.ChangeDBInfo) error
|
||||||
ChangePassword(info dto.ChangeDBInfo) error
|
ChangePassword(info dto.ChangeDBInfo) error
|
||||||
UpdateVariables(updates []dto.MysqlVariablesUpdate) error
|
UpdateVariables(updates []dto.MysqlVariablesUpdate) error
|
||||||
@ -89,9 +90,6 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
|||||||
if req.From == "local" && req.Username == "root" {
|
if req.From == "local" && req.Username == "root" {
|
||||||
return nil, errors.New("Cannot set root as user name")
|
return nil, errors.New("Cannot set root as user name")
|
||||||
}
|
}
|
||||||
if req.From == "127.0.0.1" {
|
|
||||||
return nil, errors.New("Cannot set 127.0.0.1 as address")
|
|
||||||
}
|
|
||||||
|
|
||||||
cli, version, err := LoadMysqlClientByFrom(req.From)
|
cli, version, err := LoadMysqlClientByFrom(req.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -127,22 +125,57 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
|||||||
return &createItem, nil
|
return &createItem, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *MysqlService) LoadFromRemote(from string) error {
|
||||||
|
client, version, err := LoadMysqlClientByFrom(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
databases, err := mysqlRepo.List(remoteDBRepo.WithByFrom(from))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
datas, err := client.SyncDB(version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, data := range datas {
|
||||||
|
hasOld := false
|
||||||
|
for _, oldData := range databases {
|
||||||
|
if oldData.Name == data.Name {
|
||||||
|
hasOld = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasOld {
|
||||||
|
var createItem model.DatabaseMysql
|
||||||
|
if err := copier.Copy(&createItem, &data); err != nil {
|
||||||
|
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
if err := mysqlRepo.Create(context.Background(), &createItem); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
|
func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
|
||||||
return mysqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
return mysqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
|
func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
|
||||||
var appInUsed []string
|
var appInUsed []string
|
||||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
|
||||||
if err != nil {
|
|
||||||
return appInUsed, err
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err := mysqlRepo.Get(commonRepo.WithByID(id))
|
db, err := mysqlRepo.Get(commonRepo.WithByID(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return appInUsed, err
|
return appInUsed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if db.From == "local" {
|
||||||
|
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||||
|
if err != nil {
|
||||||
|
return appInUsed, err
|
||||||
|
}
|
||||||
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(db.ID))
|
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(db.ID))
|
||||||
for _, app := range apps {
|
for _, app := range apps {
|
||||||
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
||||||
@ -150,6 +183,16 @@ func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
|
|||||||
appInUsed = append(appInUsed, appInstall.Name)
|
appInUsed = append(appInUsed, appInstall.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID))
|
||||||
|
for _, app := range apps {
|
||||||
|
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
||||||
|
if appInstall.ID != 0 {
|
||||||
|
appInUsed = append(appInUsed, appInstall.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return appInUsed, nil
|
return appInUsed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"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/mysql"
|
"github.com/1Panel-dev/1Panel/backend/utils/mysql"
|
||||||
@ -12,6 +14,7 @@ import (
|
|||||||
type RemoteDBService struct{}
|
type RemoteDBService struct{}
|
||||||
|
|
||||||
type IRemoteDBService interface {
|
type IRemoteDBService interface {
|
||||||
|
Get(name string) (dto.RemoteDBInfo, error)
|
||||||
SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error)
|
SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error)
|
||||||
Create(req dto.RemoteDBCreate) error
|
Create(req dto.RemoteDBCreate) error
|
||||||
Update(req dto.RemoteDBUpdate) error
|
Update(req dto.RemoteDBUpdate) error
|
||||||
@ -40,6 +43,18 @@ func (u *RemoteDBService) SearchWithPage(search dto.RemoteDBSearch) (int64, inte
|
|||||||
return total, datas, err
|
return total, datas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *RemoteDBService) Get(name string) (dto.RemoteDBInfo, error) {
|
||||||
|
var data dto.RemoteDBInfo
|
||||||
|
remote, err := remoteDBRepo.Get(commonRepo.WithByName(name))
|
||||||
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
if err := copier.Copy(&data, &remote); err != nil {
|
||||||
|
return data, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
|
func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
|
||||||
dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType))
|
dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType))
|
||||||
var datas []dto.RemoteDBOption
|
var datas []dto.RemoteDBOption
|
||||||
@ -82,7 +97,15 @@ func (u *RemoteDBService) Delete(id uint) error {
|
|||||||
if db.ID == 0 {
|
if db.ID == 0 {
|
||||||
return constant.ErrRecordNotFound
|
return constant.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
return remoteDBRepo.Delete(commonRepo.WithByID(id))
|
if err := remoteDBRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.From != "local" {
|
||||||
|
if err := mysqlRepo.Delete(context.Background(), remoteDBRepo.WithByFrom(db.Name)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *RemoteDBService) Update(req dto.RemoteDBUpdate) error {
|
func (u *RemoteDBService) Update(req dto.RemoteDBUpdate) error {
|
||||||
|
@ -17,6 +17,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
|||||||
baseApi := v1.ApiGroupApp.BaseApi
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
{
|
{
|
||||||
cmdRouter.POST("", baseApi.CreateMysql)
|
cmdRouter.POST("", baseApi.CreateMysql)
|
||||||
|
cmdRouter.GET("load/:from", baseApi.LoadDBFromRemote)
|
||||||
cmdRouter.POST("/change/access", baseApi.ChangeMysqlAccess)
|
cmdRouter.POST("/change/access", baseApi.ChangeMysqlAccess)
|
||||||
cmdRouter.POST("/change/password", baseApi.ChangeMysqlPassword)
|
cmdRouter.POST("/change/password", baseApi.ChangeMysqlPassword)
|
||||||
cmdRouter.POST("/del/check", baseApi.DeleteCheckMysql)
|
cmdRouter.POST("/del/check", baseApi.DeleteCheckMysql)
|
||||||
@ -42,6 +43,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
|||||||
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
|
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
|
||||||
|
|
||||||
cmdRouter.POST("/remote", baseApi.CreateRemoteDB)
|
cmdRouter.POST("/remote", baseApi.CreateRemoteDB)
|
||||||
|
cmdRouter.GET("/remote/:name", baseApi.GetRemoteDB)
|
||||||
cmdRouter.GET("/remote/list/:type", baseApi.ListRemoteDB)
|
cmdRouter.GET("/remote/list/:type", baseApi.ListRemoteDB)
|
||||||
cmdRouter.POST("/remote/update", baseApi.UpdateRemoteDB)
|
cmdRouter.POST("/remote/update", baseApi.UpdateRemoteDB)
|
||||||
cmdRouter.POST("/remote/search", baseApi.SearchRemoteDB)
|
cmdRouter.POST("/remote/search", baseApi.SearchRemoteDB)
|
||||||
|
@ -20,6 +20,7 @@ type MysqlClient interface {
|
|||||||
Backup(info client.BackupInfo) error
|
Backup(info client.BackupInfo) error
|
||||||
Recover(info client.RecoverInfo) error
|
Recover(info client.RecoverInfo) error
|
||||||
|
|
||||||
|
SyncDB(version string) ([]client.SyncDBInfo, error)
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
|
|||||||
return nil, buserr.New(constant.ErrCmdIllegal)
|
return nil, buserr.New(constant.ErrCmdIllegal)
|
||||||
}
|
}
|
||||||
connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password, "-e"}
|
connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password, "-e"}
|
||||||
return client.NewLocal(connArgs, conn.Address, conn.Password), nil
|
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.From), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
|
connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
|
||||||
@ -42,6 +43,7 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
|
|||||||
}
|
}
|
||||||
return client.NewRemote(client.Remote{
|
return client.NewRemote(client.Remote{
|
||||||
Client: db,
|
Client: db,
|
||||||
|
From: conn.From,
|
||||||
User: conn.Username,
|
User: conn.Username,
|
||||||
Password: conn.Password,
|
Password: conn.Password,
|
||||||
Address: conn.Address,
|
Address: conn.Address,
|
||||||
|
@ -69,6 +69,16 @@ type RecoverInfo struct {
|
|||||||
Timeout uint `json:"timeout"` // second
|
Timeout uint `json:"timeout"` // second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SyncDBInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
From string `json:"from"`
|
||||||
|
MysqlName string `json:"mysqlName"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Permission string `json:"permission"`
|
||||||
|
}
|
||||||
|
|
||||||
var formatMap = map[string]string{
|
var formatMap = map[string]string{
|
||||||
"utf8": "utf8_general_ci",
|
"utf8": "utf8_general_ci",
|
||||||
"utf8mb4": "utf8mb4_general_ci",
|
"utf8mb4": "utf8mb4_general_ci",
|
||||||
|
@ -13,17 +13,19 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"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/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Local struct {
|
type Local struct {
|
||||||
PrefixCommand []string
|
PrefixCommand []string
|
||||||
|
From string
|
||||||
Password string
|
Password string
|
||||||
ContainerName string
|
ContainerName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLocal(command []string, containerName, password string) *Local {
|
func NewLocal(command []string, containerName, password, from string) *Local {
|
||||||
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password}
|
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password, From: from}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Local) Create(info CreateInfo) error {
|
func (r *Local) Create(info CreateInfo) error {
|
||||||
@ -252,6 +254,81 @@ func (r *Local) Recover(info RecoverInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||||
|
var datas []SyncDBInfo
|
||||||
|
lines, err := r.ExecSQLForRows("SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA", 300)
|
||||||
|
if err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
for _, line := range lines {
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if parts[0] == "SCHEMA_NAME" || parts[0] == "information_schema" || parts[0] == "mysql" || parts[0] == "performance_schema" || parts[0] == "sys" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dataItem := SyncDBInfo{
|
||||||
|
Name: parts[0],
|
||||||
|
From: r.From,
|
||||||
|
MysqlName: r.From,
|
||||||
|
Format: parts[1],
|
||||||
|
}
|
||||||
|
userLines, err := r.ExecSQLForRows(fmt.Sprintf("SELECT USER,HOST FROM mysql.DB WHERE DB = '%s'", parts[0]), 300)
|
||||||
|
if err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var permissionItem []string
|
||||||
|
isLocal := true
|
||||||
|
i := 0
|
||||||
|
for _, userline := range userLines {
|
||||||
|
userparts := strings.Fields(userline)
|
||||||
|
if len(userparts) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if userparts[0] == "root" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
dataItem.Username = userparts[0]
|
||||||
|
}
|
||||||
|
dataItem.Username = userparts[0]
|
||||||
|
if dataItem.Username == userparts[0] && userparts[1] == "%" {
|
||||||
|
isLocal = false
|
||||||
|
dataItem.Permission = "%"
|
||||||
|
} else if dataItem.Username == userparts[0] && userparts[1] != "localhost" {
|
||||||
|
isLocal = false
|
||||||
|
permissionItem = append(permissionItem, userparts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(dataItem.Username) == 0 {
|
||||||
|
if err := r.CreateUser(CreateInfo{
|
||||||
|
Name: parts[0],
|
||||||
|
Format: parts[1],
|
||||||
|
Version: version,
|
||||||
|
Username: parts[0],
|
||||||
|
Password: common.RandStr(16),
|
||||||
|
Permission: "%",
|
||||||
|
Timeout: 300,
|
||||||
|
}); err != nil {
|
||||||
|
global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err)
|
||||||
|
}
|
||||||
|
dataItem.Username = parts[0]
|
||||||
|
dataItem.Permission = "%"
|
||||||
|
} else {
|
||||||
|
if isLocal {
|
||||||
|
dataItem.Permission = "localhost"
|
||||||
|
}
|
||||||
|
if len(dataItem.Permission) == 0 {
|
||||||
|
dataItem.Permission = strings.Join(permissionItem, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datas = append(datas, dataItem)
|
||||||
|
}
|
||||||
|
return datas, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Local) Close() {}
|
func (r *Local) Close() {}
|
||||||
|
|
||||||
func (r *Local) ExecSQL(command string, timeout uint) error {
|
func (r *Local) ExecSQL(command string, timeout uint) error {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"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/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
|
||||||
"github.com/jarvanstack/mysqldump"
|
"github.com/jarvanstack/mysqldump"
|
||||||
@ -19,6 +20,7 @@ import (
|
|||||||
|
|
||||||
type Remote struct {
|
type Remote struct {
|
||||||
Client *sql.DB
|
Client *sql.DB
|
||||||
|
From string
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
Address string
|
Address string
|
||||||
@ -251,6 +253,86 @@ func (r *Remote) Recover(info RecoverInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||||
|
var datas []SyncDBInfo
|
||||||
|
rows, err := r.Client.Query("SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA")
|
||||||
|
if err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var dbName, charsetName string
|
||||||
|
if err = rows.Scan(&dbName, &charsetName); err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
if dbName == "information_schema" || dbName == "mysql" || dbName == "performance_schema" || dbName == "sys" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dataItem := SyncDBInfo{
|
||||||
|
Name: dbName,
|
||||||
|
From: r.From,
|
||||||
|
MysqlName: r.From,
|
||||||
|
Format: charsetName,
|
||||||
|
}
|
||||||
|
userRows, err := r.Client.Query("SELECT USER,HOST FROM mysql.DB WHERE DB = ?", dbName)
|
||||||
|
if err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var permissionItem []string
|
||||||
|
isLocal := true
|
||||||
|
i := 0
|
||||||
|
for userRows.Next() {
|
||||||
|
var user, host string
|
||||||
|
if err = userRows.Scan(&user, &host); err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
if user == "root" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
dataItem.Username = user
|
||||||
|
}
|
||||||
|
if dataItem.Username == user && host == "%" {
|
||||||
|
isLocal = false
|
||||||
|
dataItem.Permission = "%"
|
||||||
|
} else if dataItem.Username == user && host != "localhost" {
|
||||||
|
isLocal = false
|
||||||
|
permissionItem = append(permissionItem, host)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if len(dataItem.Username) == 0 {
|
||||||
|
if err := r.CreateUser(CreateInfo{
|
||||||
|
Name: dbName,
|
||||||
|
Format: charsetName,
|
||||||
|
Version: version,
|
||||||
|
Username: dbName,
|
||||||
|
Password: common.RandStr(16),
|
||||||
|
Permission: "%",
|
||||||
|
Timeout: 300,
|
||||||
|
}); err != nil {
|
||||||
|
global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err)
|
||||||
|
}
|
||||||
|
dataItem.Username = dbName
|
||||||
|
dataItem.Permission = "%"
|
||||||
|
} else {
|
||||||
|
if isLocal {
|
||||||
|
dataItem.Permission = "localhost"
|
||||||
|
}
|
||||||
|
if len(dataItem.Permission) == 0 {
|
||||||
|
dataItem.Permission = strings.Join(permissionItem, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datas = append(datas, dataItem)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return datas, err
|
||||||
|
}
|
||||||
|
return datas, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Remote) Close() {
|
func (r *Remote) Close() {
|
||||||
_ = r.Client.Close()
|
_ = r.Client.Close()
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ export const addMysqlDB = (params: Database.MysqlDBCreate) => {
|
|||||||
}
|
}
|
||||||
return http.post(`/databases`, reqest);
|
return http.post(`/databases`, reqest);
|
||||||
};
|
};
|
||||||
|
export const loadDBFromRemote = (from: string) => {
|
||||||
|
return http.get(`/databases/load/${from}`);
|
||||||
|
};
|
||||||
export const updateMysqlAccess = (params: Database.ChangeInfo) => {
|
export const updateMysqlAccess = (params: Database.ChangeInfo) => {
|
||||||
return http.post(`/databases/change/access`, params);
|
return http.post(`/databases/change/access`, params);
|
||||||
};
|
};
|
||||||
@ -85,6 +88,9 @@ export const updateRedisConfByFile = (params: Database.RedisConfUpdateByFile) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// remote
|
// remote
|
||||||
|
export const getRemoteDB = (name: string) => {
|
||||||
|
return http.get<Database.RemoteDBInfo>(`/databases/remote/${name}`);
|
||||||
|
};
|
||||||
export const searchRemoteDBs = (params: Database.SearchRemoteDBPage) => {
|
export const searchRemoteDBs = (params: Database.SearchRemoteDBPage) => {
|
||||||
return http.post<ResPage<Database.RemoteDBInfo>>(`/databases/remote/search`, params);
|
return http.post<ResPage<Database.RemoteDBInfo>>(`/databases/remote/search`, params);
|
||||||
};
|
};
|
||||||
|
@ -335,15 +335,16 @@ const message = {
|
|||||||
portHelper:
|
portHelper:
|
||||||
'This port is the exposed port of the container. You need to save the modification separately and restart the container!',
|
'This port is the exposed port of the container. You need to save the modification separately and restart the container!',
|
||||||
|
|
||||||
|
loadFromRemote: 'load from Server',
|
||||||
|
passwordHelper: 'Unable to retrieve, please modify',
|
||||||
remote: 'Remote',
|
remote: 'Remote',
|
||||||
remoteDB: 'Remote DB',
|
remoteDB: 'Remote DB',
|
||||||
createRemoteDB: 'Create Remote DB',
|
createRemoteDB: 'Create Remote Server',
|
||||||
editRemoteDB: 'Edit Remote DB',
|
editRemoteDB: 'Edit Remote Server',
|
||||||
localDB: 'Local DB',
|
localDB: 'Local DB',
|
||||||
address: 'DB address',
|
address: 'DB address',
|
||||||
version: 'DB version',
|
version: 'DB version',
|
||||||
versionHelper: 'Currently, only versions 5.6, 5.7, and 8.0 are supported',
|
versionHelper: 'Currently, only versions 5.6, 5.7, and 8.0 are supported',
|
||||||
addressHelper: 'The remote database address except 127.0.0.1.',
|
|
||||||
userHelper: 'The root user or a database user with root privileges can access the remote database.',
|
userHelper: 'The root user or a database user with root privileges can access the remote database.',
|
||||||
|
|
||||||
selectFile: 'Select file',
|
selectFile: 'Select file',
|
||||||
|
@ -330,15 +330,16 @@ const message = {
|
|||||||
|
|
||||||
confChange: '配置修改',
|
confChange: '配置修改',
|
||||||
|
|
||||||
|
loadFromRemote: '從服務器獲取',
|
||||||
|
passwordHelper: '無法獲取密碼,請修改',
|
||||||
remote: '遠程',
|
remote: '遠程',
|
||||||
remoteDB: '遠程數據庫',
|
remoteDB: '遠程服務器',
|
||||||
createRemoteDB: '創建遠程數據庫',
|
createRemoteDB: '添加遠程服務器',
|
||||||
editRemoteDB: '編輯遠程數據庫',
|
editRemoteDB: '編輯遠程服務器',
|
||||||
localDB: '本地數據庫',
|
localDB: '本地數據庫',
|
||||||
address: '數據庫地址',
|
address: '數據庫地址',
|
||||||
version: '數據庫版本',
|
version: '數據庫版本',
|
||||||
versionHelper: '當前僅支持 5.6 5.7 8.0 三個版本',
|
versionHelper: '當前僅支持 5.6 5.7 8.0 三個版本',
|
||||||
addressHelper: '非 127.0.0.1 的遠程數據庫地址',
|
|
||||||
userHelper: 'root 用戶或者擁有 root 權限的數據庫用戶',
|
userHelper: 'root 用戶或者擁有 root 權限的數據庫用戶',
|
||||||
|
|
||||||
selectFile: '選擇文件',
|
selectFile: '選擇文件',
|
||||||
|
@ -330,15 +330,16 @@ const message = {
|
|||||||
|
|
||||||
confChange: '配置修改',
|
confChange: '配置修改',
|
||||||
|
|
||||||
|
loadFromRemote: '从服务器获取',
|
||||||
|
passwordHelper: '无法获取密码,请修改',
|
||||||
remote: '远程',
|
remote: '远程',
|
||||||
remoteDB: '远程数据库',
|
remoteDB: '远程服务器',
|
||||||
createRemoteDB: '创建远程数据库',
|
createRemoteDB: '添加远程服务器',
|
||||||
editRemoteDB: '编辑远程数据库',
|
editRemoteDB: '编辑远程服务器',
|
||||||
localDB: '本地数据库',
|
localDB: '本地数据库',
|
||||||
address: '数据库地址',
|
address: '数据库地址',
|
||||||
version: '数据库版本',
|
version: '数据库版本',
|
||||||
versionHelper: '当前仅支持 5.6 5.7 8.0 三个版本',
|
versionHelper: '当前仅支持 5.6 5.7 8.0 三个版本',
|
||||||
addressHelper: '非 127.0.0.1 的远程数据库地址',
|
|
||||||
userHelper: 'root 用户或者拥有 root 权限的数据库用户',
|
userHelper: 'root 用户或者拥有 root 权限的数据库用户',
|
||||||
|
|
||||||
selectFile: '选择文件',
|
selectFile: '选择文件',
|
||||||
|
@ -454,7 +454,7 @@ const loadContainers = async () => {
|
|||||||
|
|
||||||
const checkMysqlInstalled = async () => {
|
const checkMysqlInstalled = async () => {
|
||||||
const data = await loadDBNames();
|
const data = await loadDBNames();
|
||||||
mysqlInfo.dbNames = data.data;
|
mysqlInfo.dbNames = data.data || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
function isBackup() {
|
function isBackup() {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<DrawerHeader :header="$t('database.databaseConnInfo')" :back="handleClose" />
|
<DrawerHeader :header="$t('database.databaseConnInfo')" :back="handleClose" />
|
||||||
</template>
|
</template>
|
||||||
<el-form @submit.prevent v-loading="loading" ref="formRef" :model="form" label-position="top">
|
<el-form @submit.prevent v-loading="loading" ref="formRef" :model="form" label-position="top">
|
||||||
<el-row type="flex" justify="center">
|
<el-row type="flex" justify="center" v-if="form.from === 'local'">
|
||||||
<el-col :span="22">
|
<el-col :span="22">
|
||||||
<el-form-item :label="$t('database.containerConn')">
|
<el-form-item :label="$t('database.containerConn')">
|
||||||
<el-tag>
|
<el-tag>
|
||||||
@ -39,6 +39,19 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-row type="flex" justify="center" v-if="form.from !== 'local'">
|
||||||
|
<el-col :span="22">
|
||||||
|
<el-form-item :label="$t('database.remoteConn')">
|
||||||
|
<el-tag>{{ form.remoteIP + ':' + form.port }}</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('commons.login.username')">
|
||||||
|
<el-tag>{{ form.username }}</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('commons.login.password')">
|
||||||
|
<el-tag>{{ form.password }}</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit" @cancel="loadPassword"></ConfirmDialog>
|
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit" @cancel="loadPassword"></ConfirmDialog>
|
||||||
@ -58,28 +71,31 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm } from 'element-plus';
|
||||||
import { loadRemoteAccess, updateMysqlAccess, updateMysqlPassword } from '@/api/modules/database';
|
import { getRemoteDB, loadRemoteAccess, updateMysqlAccess, updateMysqlPassword } from '@/api/modules/database';
|
||||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||||
import { GetAppConnInfo } from '@/api/modules/app';
|
import { GetAppConnInfo } from '@/api/modules/app';
|
||||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||||
import { getRandomStr } from '@/utils/util';
|
import { getRandomStr } from '@/utils/util';
|
||||||
import { App } from '@/api/interface/app';
|
|
||||||
import useClipboard from 'vue-clipboard3';
|
import useClipboard from 'vue-clipboard3';
|
||||||
const { toClipboard } = useClipboard();
|
const { toClipboard } = useClipboard();
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const dialogVisiable = ref(false);
|
const dialogVisiable = ref(false);
|
||||||
const form = ref<App.DatabaseConnInfo>({
|
const form = reactive({
|
||||||
password: '',
|
password: '',
|
||||||
serviceName: '',
|
serviceName: '',
|
||||||
privilege: false,
|
privilege: false,
|
||||||
port: 0,
|
port: 0,
|
||||||
|
|
||||||
|
from: '',
|
||||||
|
username: '',
|
||||||
|
remoteIP: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const confirmDialogRef = ref();
|
const confirmDialogRef = ref();
|
||||||
@ -88,15 +104,24 @@ const confirmAccessDialogRef = ref();
|
|||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
const acceptParams = (): void => {
|
interface DialogProps {
|
||||||
form.value.password = '';
|
from: string;
|
||||||
|
remoteIP: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const acceptParams = (param: DialogProps): void => {
|
||||||
|
form.password = '';
|
||||||
|
form.from = param.from;
|
||||||
|
if (form.from !== 'local') {
|
||||||
|
loadRemoteInfo();
|
||||||
|
}
|
||||||
loadPassword();
|
loadPassword();
|
||||||
loadAccess();
|
loadAccess();
|
||||||
dialogVisiable.value = true;
|
dialogVisiable.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const random = async () => {
|
const random = async () => {
|
||||||
form.value.password = getRandomStr(16);
|
form.password = getRandomStr(16);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCopy = async (value: string) => {
|
const onCopy = async (value: string) => {
|
||||||
@ -114,18 +139,27 @@ const handleClose = () => {
|
|||||||
|
|
||||||
const loadAccess = async () => {
|
const loadAccess = async () => {
|
||||||
const res = await loadRemoteAccess();
|
const res = await loadRemoteAccess();
|
||||||
form.value.privilege = res.data;
|
form.privilege = res.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadRemoteInfo = async () => {
|
||||||
|
const res = await getRemoteDB(form.from);
|
||||||
|
form.remoteIP = res.data.address;
|
||||||
|
form.username = res.data.username;
|
||||||
|
form.password = res.data.password;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadPassword = async () => {
|
const loadPassword = async () => {
|
||||||
const res = await GetAppConnInfo('mysql');
|
const res = await GetAppConnInfo('mysql');
|
||||||
form.value = res.data;
|
form.password = res.data.password || '';
|
||||||
|
form.port = res.data.port || 3306;
|
||||||
|
form.serviceName = res.data.serviceName || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
let param = {
|
let param = {
|
||||||
id: 0,
|
id: 0,
|
||||||
value: form.value.password,
|
value: form.password,
|
||||||
};
|
};
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await updateMysqlPassword(param)
|
await updateMysqlPassword(param)
|
||||||
@ -155,7 +189,7 @@ const onSave = async (formEl: FormInstance | undefined) => {
|
|||||||
const onSubmitAccess = async () => {
|
const onSubmitAccess = async () => {
|
||||||
let param = {
|
let param = {
|
||||||
id: 0,
|
id: 0,
|
||||||
value: form.value.privilege ? '%' : 'localhost',
|
value: form.privilege ? '%' : 'localhost',
|
||||||
};
|
};
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await updateMysqlAccess(param)
|
await updateMysqlAccess(param)
|
@ -38,13 +38,16 @@
|
|||||||
>
|
>
|
||||||
{{ $t('database.create') }}
|
{{ $t('database.create') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button @click="onChangeConn" type="primary" plain>
|
||||||
|
{{ $t('database.databaseConnInfo') }}
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="mysqlIsExist && mysqlStatus === 'Running' && isLocal()"
|
v-if="(mysqlIsExist && mysqlStatus === 'Running') || !isLocal()"
|
||||||
@click="onChangeRootPassword"
|
@click="loadDB"
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
>
|
>
|
||||||
{{ $t('database.databaseConnInfo') }}
|
{{ $t('database.loadFromRemote') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="goRemoteDB" type="primary" plain>
|
<el-button @click="goRemoteDB" type="primary" plain>
|
||||||
{{ $t('database.remoteDB') }}
|
{{ $t('database.remoteDB') }}
|
||||||
@ -83,15 +86,10 @@
|
|||||||
:class="{ mask: mysqlStatus != 'Running' && isLocal() }"
|
:class="{ mask: mysqlStatus != 'Running' && isLocal() }"
|
||||||
>
|
>
|
||||||
<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="from">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<span>{{ row.from === 'local' ? $t('database.localDB') : row.from }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column :label="$t('commons.login.username')" prop="username" />
|
<el-table-column :label="$t('commons.login.username')" prop="username" />
|
||||||
<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>
|
<div v-if="row.password">
|
||||||
<span style="float: left; line-height: 25px" v-if="!row.showPassword">***********</span>
|
<span style="float: left; line-height: 25px" v-if="!row.showPassword">***********</span>
|
||||||
<div style="cursor: pointer; float: left" v-if="!row.showPassword">
|
<div style="cursor: pointer; float: left" v-if="!row.showPassword">
|
||||||
<el-icon
|
<el-icon
|
||||||
@ -104,20 +102,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<span style="float: left" v-if="row.showPassword">{{ row.password }}</span>
|
<span style="float: left" v-if="row.showPassword">{{ row.password }}</span>
|
||||||
<div style="cursor: pointer; float: left" v-if="row.showPassword">
|
<div style="cursor: pointer; float: left" v-if="row.showPassword">
|
||||||
<el-icon
|
<el-icon class="iconInTable" @click="row.showPassword = false" :size="16">
|
||||||
style="margin-left: 5px; margin-top: 3px"
|
|
||||||
@click="row.showPassword = false"
|
|
||||||
:size="16"
|
|
||||||
>
|
|
||||||
<Hide />
|
<Hide />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div style="cursor: pointer; float: left">
|
<div style="cursor: pointer; float: left">
|
||||||
<el-icon style="margin-left: 5px; margin-top: 3px" :size="16" @click="onCopy(row)">
|
<el-icon class="iconInTable" :size="16" @click="onCopy(row)">
|
||||||
<DocumentCopy />
|
<DocumentCopy />
|
||||||
</el-icon>
|
</el-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">
|
||||||
@ -191,7 +190,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<PasswordDialog ref="passwordRef" @search="search" />
|
<PasswordDialog ref="passwordRef" @search="search" />
|
||||||
<RootPasswordDialog ref="rootPasswordRef" />
|
<RootPasswordDialog ref="connRef" />
|
||||||
<UploadDialog ref="uploadRef" />
|
<UploadDialog ref="uploadRef" />
|
||||||
<OperateDialog @search="search" ref="dialogRef" />
|
<OperateDialog @search="search" ref="dialogRef" />
|
||||||
<Backups ref="dialogBackupRef" />
|
<Backups ref="dialogBackupRef" />
|
||||||
@ -207,7 +206,7 @@
|
|||||||
import OperateDialog from '@/views/database/mysql/create/index.vue';
|
import OperateDialog from '@/views/database/mysql/create/index.vue';
|
||||||
import DeleteDialog from '@/views/database/mysql/delete/index.vue';
|
import DeleteDialog from '@/views/database/mysql/delete/index.vue';
|
||||||
import PasswordDialog from '@/views/database/mysql/password/index.vue';
|
import PasswordDialog from '@/views/database/mysql/password/index.vue';
|
||||||
import RootPasswordDialog from '@/views/database/mysql/root-password/index.vue';
|
import RootPasswordDialog from '@/views/database/mysql/conn/index.vue';
|
||||||
import AppResources from '@/views/database/mysql/check/index.vue';
|
import AppResources from '@/views/database/mysql/check/index.vue';
|
||||||
import Setting from '@/views/database/mysql/setting/index.vue';
|
import Setting from '@/views/database/mysql/setting/index.vue';
|
||||||
import AppStatus from '@/components/app-status/index.vue';
|
import AppStatus from '@/components/app-status/index.vue';
|
||||||
@ -216,7 +215,13 @@ import UploadDialog from '@/components/upload/index.vue';
|
|||||||
import PortJumpDialog from '@/components/port-jump/index.vue';
|
import PortJumpDialog from '@/components/port-jump/index.vue';
|
||||||
import { dateFormat } from '@/utils/util';
|
import { dateFormat } from '@/utils/util';
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
import { deleteCheckMysqlDB, listRemoteDBs, searchMysqlDBs, updateMysqlDescription } from '@/api/modules/database';
|
import {
|
||||||
|
deleteCheckMysqlDB,
|
||||||
|
listRemoteDBs,
|
||||||
|
loadDBFromRemote,
|
||||||
|
searchMysqlDBs,
|
||||||
|
updateMysqlDescription,
|
||||||
|
} from '@/api/modules/database';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { Database } from '@/api/interface/database';
|
import { Database } from '@/api/interface/database';
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
@ -268,9 +273,9 @@ const dialogBackupRef = ref();
|
|||||||
|
|
||||||
const uploadRef = ref();
|
const uploadRef = ref();
|
||||||
|
|
||||||
const rootPasswordRef = ref();
|
const connRef = ref();
|
||||||
const onChangeRootPassword = async () => {
|
const onChangeConn = async () => {
|
||||||
rootPasswordRef.value!.acceptParams();
|
connRef.value!.acceptParams({ from: paginationConfig.from });
|
||||||
};
|
};
|
||||||
|
|
||||||
const goRemoteDB = async () => {
|
const goRemoteDB = async () => {
|
||||||
@ -308,6 +313,18 @@ const search = async (column?: any) => {
|
|||||||
paginationConfig.total = res.data.total;
|
paginationConfig.total = res.data.total;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadDB = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
await loadDBFromRemote(paginationConfig.from)
|
||||||
|
.then(() => {
|
||||||
|
loading.value = false;
|
||||||
|
search();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const goRouter = async () => {
|
const goRouter = async () => {
|
||||||
router.push({ name: 'AppDetail', params: { appKey: 'mysql' } });
|
router.push({ name: 'AppDetail', params: { appKey: 'mysql' } });
|
||||||
};
|
};
|
||||||
@ -376,10 +393,7 @@ const onDelete = async (row: Database.MysqlDBInfo) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const buttons = [
|
const onChangePassword = async (row: Database.MysqlDBInfo) => {
|
||||||
{
|
|
||||||
label: i18n.global.t('database.changePassword'),
|
|
||||||
click: (row: Database.MysqlDBInfo) => {
|
|
||||||
let param = {
|
let param = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
from: row.from,
|
from: row.from,
|
||||||
@ -389,10 +403,20 @@ const buttons = [
|
|||||||
password: row.password,
|
password: row.password,
|
||||||
};
|
};
|
||||||
passwordRef.value.acceptParams(param);
|
passwordRef.value.acceptParams(param);
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
label: i18n.global.t('database.changePassword'),
|
||||||
|
click: (row: Database.MysqlDBInfo) => {
|
||||||
|
onChangePassword(row);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: i18n.global.t('database.permission'),
|
label: i18n.global.t('database.permission'),
|
||||||
|
disabled: (row: Database.MysqlDBInfo) => {
|
||||||
|
return !row.password;
|
||||||
|
},
|
||||||
click: (row: Database.MysqlDBInfo) => {
|
click: (row: Database.MysqlDBInfo) => {
|
||||||
let param = {
|
let param = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
@ -403,7 +427,7 @@ const buttons = [
|
|||||||
privilegeIPs: '',
|
privilegeIPs: '',
|
||||||
password: '',
|
password: '',
|
||||||
};
|
};
|
||||||
if (row.permission === '%') {
|
if (row.permission === '%' || row.permission === 'localhost') {
|
||||||
param.privilege = row.permission;
|
param.privilege = row.permission;
|
||||||
} else {
|
} else {
|
||||||
param.privilegeIPs = row.permission;
|
param.privilegeIPs = row.permission;
|
||||||
@ -446,3 +470,10 @@ onMounted(() => {
|
|||||||
loadDBOptions();
|
loadDBOptions();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.iconInTable {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -29,6 +29,11 @@
|
|||||||
<el-form-item :label="$t('database.permission')" prop="privilege">
|
<el-form-item :label="$t('database.permission')" prop="privilege">
|
||||||
<el-select style="width: 100%" v-model="changeForm.privilege">
|
<el-select style="width: 100%" v-model="changeForm.privilege">
|
||||||
<el-option value="%" :label="$t('database.permissionAll')" />
|
<el-option value="%" :label="$t('database.permissionAll')" />
|
||||||
|
<el-option
|
||||||
|
v-if="changeForm.from !== 'local'"
|
||||||
|
value="localhost"
|
||||||
|
:label="$t('terminal.localhost')"
|
||||||
|
/>
|
||||||
<el-option value="ip" :label="$t('database.permissionForIP')" />
|
<el-option value="ip" :label="$t('database.permissionForIP')" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -110,6 +115,7 @@ const acceptParams = (params: DialogProps): void => {
|
|||||||
: i18n.global.t('database.permission');
|
: i18n.global.t('database.permission');
|
||||||
changeForm.id = params.id;
|
changeForm.id = params.id;
|
||||||
changeForm.from = params.from;
|
changeForm.from = params.from;
|
||||||
|
console.log(changeForm.from);
|
||||||
changeForm.mysqlName = params.mysqlName;
|
changeForm.mysqlName = params.mysqlName;
|
||||||
changeForm.userName = params.username;
|
changeForm.userName = params.username;
|
||||||
changeForm.password = params.password;
|
changeForm.password = params.password;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||||
<template #header>
|
<template #header>
|
||||||
<DrawerHeader :header="title" :resource="dialogData.rowData?.name" :back="handleClose" />
|
<DrawerHeader :header="title" :resource="dialogData.rowData?.name" :back="handleClose" />
|
||||||
</template>
|
</template>
|
||||||
@ -7,7 +7,12 @@
|
|||||||
<el-row type="flex" justify="center">
|
<el-row type="flex" justify="center">
|
||||||
<el-col :span="22">
|
<el-col :span="22">
|
||||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||||
<el-input clearable v-model.trim="dialogData.rowData!.name" />
|
<el-input
|
||||||
|
v-if="dialogData.title === 'create'"
|
||||||
|
clearable
|
||||||
|
v-model.trim="dialogData.rowData!.name"
|
||||||
|
/>
|
||||||
|
<el-tag v-else>{{ dialogData.rowData!.name }}</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('database.version')" prop="version">
|
<el-form-item :label="$t('database.version')" prop="version">
|
||||||
<el-select v-model="dialogData.rowData!.version">
|
<el-select v-model="dialogData.rowData!.version">
|
||||||
@ -19,7 +24,6 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('database.address')" prop="address">
|
<el-form-item :label="$t('database.address')" prop="address">
|
||||||
<el-input clearable v-model.trim="dialogData.rowData!.address" />
|
<el-input clearable v-model.trim="dialogData.rowData!.address" />
|
||||||
<span class="input-help">{{ $t('database.addressHelper') }}</span>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('commons.table.port')" prop="port">
|
<el-form-item :label="$t('commons.table.port')" prop="port">
|
||||||
<el-input clearable v-model.trim="dialogData.rowData!.port" />
|
<el-input clearable v-model.trim="dialogData.rowData!.port" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user