mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
feat: 远程数据库支持添加 mariadb (#2139)
This commit is contained in:
parent
66c824a841
commit
149d44dbbe
@ -244,6 +244,7 @@ type DatabaseInfo struct {
|
|||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Name string `json:"name" validate:"max=256"`
|
Name string `json:"name" validate:"max=256"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
|
Type string `json:"type"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Port uint `json:"port"`
|
Port uint `json:"port"`
|
||||||
@ -263,7 +264,7 @@ type DatabaseOption struct {
|
|||||||
|
|
||||||
type DatabaseCreate struct {
|
type DatabaseCreate struct {
|
||||||
Name string `json:"name" validate:"required,max=256"`
|
Name string `json:"name" validate:"required,max=256"`
|
||||||
Type string `json:"type" validate:"required,oneof=mysql"`
|
Type string `json:"type" validate:"required"`
|
||||||
From string `json:"from" validate:"required,oneof=local remote"`
|
From string `json:"from" validate:"required,oneof=local remote"`
|
||||||
Version string `json:"version" validate:"required"`
|
Version string `json:"version" validate:"required"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
|
@ -2,6 +2,8 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@ -18,9 +20,8 @@ type IDatabaseRepo interface {
|
|||||||
Get(opts ...DBOption) (model.Database, error)
|
Get(opts ...DBOption) (model.Database, error)
|
||||||
WithByFrom(from string) DBOption
|
WithByFrom(from string) DBOption
|
||||||
WithoutByFrom(from string) DBOption
|
WithoutByFrom(from string) DBOption
|
||||||
WithByMysqlList() DBOption
|
|
||||||
WithAppInstallID(appInstallID uint) DBOption
|
WithAppInstallID(appInstallID uint) DBOption
|
||||||
WithType(dbType string) DBOption
|
WithTypeList(dbType string) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIDatabaseRepo() IDatabaseRepo {
|
func NewIDatabaseRepo() IDatabaseRepo {
|
||||||
@ -59,12 +60,6 @@ func (d *DatabaseRepo) GetList(opts ...DBOption) ([]model.Database, error) {
|
|||||||
return databases, err
|
return databases, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DatabaseRepo) WithByMysqlList() DBOption {
|
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
|
||||||
return g.Where("type = ? OR type = ?", "mysql", "mariadb")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DatabaseRepo) WithByFrom(from string) DBOption {
|
func (d *DatabaseRepo) WithByFrom(from string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("`from` = ?", from)
|
return g.Where("`from` = ?", from)
|
||||||
@ -77,9 +72,18 @@ func (d *DatabaseRepo) WithoutByFrom(from string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DatabaseRepo) WithType(dbType string) DBOption {
|
func (d *DatabaseRepo) WithTypeList(dbType string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("`type` = ?", dbType)
|
types := strings.Split(dbType, ",")
|
||||||
|
if len(types) == 1 {
|
||||||
|
return g.Where("`type` = ?", dbType)
|
||||||
|
}
|
||||||
|
for _, ty := range types {
|
||||||
|
if len(ty) != 0 {
|
||||||
|
g.Or("`type` = ?", ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return g
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +428,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
|||||||
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||||
var res []response.AppService
|
var res []response.AppService
|
||||||
if DatabaseKeys[key] {
|
if DatabaseKeys[key] {
|
||||||
dbs, _ := databaseRepo.GetList(databaseRepo.WithByFrom("local"), databaseRepo.WithType(key))
|
dbs, _ := databaseRepo.GetList(databaseRepo.WithByFrom("local"), commonRepo.WithByType(key))
|
||||||
if len(dbs) == 0 {
|
if len(dbs) == 0 {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
|
||||||
"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"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
|
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
|
||||||
@ -30,7 +29,7 @@ func NewIDatabaseService() IDatabaseService {
|
|||||||
|
|
||||||
func (u *DatabaseService) SearchWithPage(search dto.DatabaseSearch) (int64, interface{}, error) {
|
func (u *DatabaseService) SearchWithPage(search dto.DatabaseSearch) (int64, interface{}, error) {
|
||||||
total, dbs, err := databaseRepo.Page(search.Page, search.PageSize,
|
total, dbs, err := databaseRepo.Page(search.Page, search.PageSize,
|
||||||
commonRepo.WithByType(search.Type),
|
databaseRepo.WithTypeList(search.Type),
|
||||||
commonRepo.WithLikeName(search.Info),
|
commonRepo.WithLikeName(search.Info),
|
||||||
databaseRepo.WithoutByFrom("local"),
|
databaseRepo.WithoutByFrom("local"),
|
||||||
)
|
)
|
||||||
@ -58,13 +57,7 @@ func (u *DatabaseService) Get(name string) (dto.DatabaseInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) {
|
func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) {
|
||||||
var opts []repo.DBOption
|
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
||||||
if dbType == "mysql" {
|
|
||||||
opts = append(opts, databaseRepo.WithByMysqlList())
|
|
||||||
} else {
|
|
||||||
opts = append(opts, commonRepo.WithByType(dbType))
|
|
||||||
}
|
|
||||||
dbs, err := databaseRepo.GetList(opts...)
|
|
||||||
var datas []dto.DatabaseOption
|
var datas []dto.DatabaseOption
|
||||||
for _, db := range dbs {
|
for _, db := range dbs {
|
||||||
var item dto.DatabaseOption
|
var item dto.DatabaseOption
|
||||||
|
@ -147,7 +147,7 @@ func (r *Local) ChangePassword(info PasswordChangeInfo) error {
|
|||||||
for _, user := range userlist {
|
for _, user := range userlist {
|
||||||
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
|
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
|
||||||
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
|
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
|
||||||
passwordChangeSql = fmt.Sprintf("alter user %s identified by '%s';", user, info.Password)
|
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED BY '%s';", user, info.Password)
|
||||||
}
|
}
|
||||||
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
|
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -152,7 +152,7 @@ func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
|
|||||||
for _, user := range userlist {
|
for _, user := range userlist {
|
||||||
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
|
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
|
||||||
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
|
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
|
||||||
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED WITH mysql_native_password BY '%s';", user, info.Password)
|
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED BY '%s';", user, info.Password)
|
||||||
}
|
}
|
||||||
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
|
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -354,7 +354,7 @@ const message = {
|
|||||||
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 {0} are supported',
|
||||||
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',
|
||||||
|
@ -346,7 +346,7 @@ const message = {
|
|||||||
localDB: '本地數據庫',
|
localDB: '本地數據庫',
|
||||||
address: '數據庫地址',
|
address: '數據庫地址',
|
||||||
version: '數據庫版本',
|
version: '數據庫版本',
|
||||||
versionHelper: '當前僅支持 5.6 5.7 8.0 三個版本',
|
versionHelper: '當前僅支持 {0} 三個版本',
|
||||||
userHelper: 'root 用戶或者擁有 root 權限的數據庫用戶',
|
userHelper: 'root 用戶或者擁有 root 權限的數據庫用戶',
|
||||||
|
|
||||||
selectFile: '選擇文件',
|
selectFile: '選擇文件',
|
||||||
|
@ -346,7 +346,7 @@ const message = {
|
|||||||
localDB: '本地数据库',
|
localDB: '本地数据库',
|
||||||
address: '数据库地址',
|
address: '数据库地址',
|
||||||
version: '数据库版本',
|
version: '数据库版本',
|
||||||
versionHelper: '当前仅支持 5.6 5.7 8.0 三个版本',
|
versionHelper: '当前仅支持 {0} 版本',
|
||||||
userHelper: 'root 用户或者拥有 root 权限的数据库用户',
|
userHelper: 'root 用户或者拥有 root 权限的数据库用户',
|
||||||
|
|
||||||
selectFile: '选择文件',
|
selectFile: '选择文件',
|
||||||
|
@ -386,7 +386,7 @@ const checkExist = (data: App.CheckInstalled) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const loadDBOptions = async () => {
|
const loadDBOptions = async () => {
|
||||||
const res = await listDatabases('mysql');
|
const res = await listDatabases('mysql,mariadb');
|
||||||
let datas = res.data || [];
|
let datas = res.data || [];
|
||||||
dbOptionsLocal.value = [];
|
dbOptionsLocal.value = [];
|
||||||
dbOptionsRemote.value = [];
|
dbOptionsRemote.value = [];
|
||||||
|
@ -121,7 +121,7 @@ const search = async (column?: any) => {
|
|||||||
page: paginationConfig.currentPage,
|
page: paginationConfig.currentPage,
|
||||||
pageSize: paginationConfig.pageSize,
|
pageSize: paginationConfig.pageSize,
|
||||||
info: searchName.value,
|
info: searchName.value,
|
||||||
type: 'mysql',
|
type: 'mysql,mariadb',
|
||||||
orderBy: paginationConfig.orderBy,
|
orderBy: paginationConfig.orderBy,
|
||||||
order: paginationConfig.order,
|
order: paginationConfig.order,
|
||||||
};
|
};
|
||||||
|
@ -19,13 +19,29 @@
|
|||||||
/>
|
/>
|
||||||
<el-tag v-else>{{ dialogData.rowData!.name }}</el-tag>
|
<el-tag v-else>{{ dialogData.rowData!.name }}</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('commons.table.type')" prop="type">
|
||||||
|
<el-select v-model="dialogData.rowData!.type" @change="changeType">
|
||||||
|
<div>
|
||||||
|
<el-option value="mysql" label="MySQL" />
|
||||||
|
<el-option value="mariadb" label="Mariadb" />
|
||||||
|
</div>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item :label="$t('database.version')" prop="version">
|
<el-form-item :label="$t('database.version')" prop="version">
|
||||||
<el-select @change="isOK = false" v-model="dialogData.rowData!.version">
|
<el-select @change="isOK = false" v-model="dialogData.rowData!.version">
|
||||||
<el-option value="5.6" label="5.6" />
|
<div v-if="dialogData.rowData!.type === 'mysql'">
|
||||||
<el-option value="5.7" label="5.7" />
|
<el-option value="5.6" label="5.6" />
|
||||||
<el-option value="8.0" label="8.0" />
|
<el-option value="5.7" label="5.7" />
|
||||||
|
<el-option value="8.x" label="8.x" />
|
||||||
|
</div>
|
||||||
|
<el-option v-else value="10.x" label="10.x" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<span class="input-help">{{ $t('database.versionHelper') }}</span>
|
<span v-if="dialogData.rowData!.type === 'mysql'" class="input-help">
|
||||||
|
{{ $t('database.versionHelper', ['5.6 5.7 8.x']) }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="input-help">
|
||||||
|
{{ $t('database.versionHelper', ['10.x']) }}
|
||||||
|
</span>
|
||||||
</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 @change="isOK = false" clearable v-model.trim="dialogData.rowData!.address" />
|
<el-input @change="isOK = false" clearable v-model.trim="dialogData.rowData!.address" />
|
||||||
@ -112,26 +128,19 @@ const rules = reactive({
|
|||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const changeType = () => {
|
||||||
|
dialogData.value.rowData.version = dialogData.value.rowData.type === 'mysql' ? '5.6' : '10.x';
|
||||||
|
isOK.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async (formEl: FormInstance | undefined, operation: string) => {
|
const onSubmit = async (formEl: FormInstance | undefined, operation: string) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
let param = {
|
dialogData.value.rowData.from = 'remote';
|
||||||
id: dialogData.value.rowData.id,
|
|
||||||
name: dialogData.value.rowData.name,
|
|
||||||
type: 'mysql',
|
|
||||||
version: dialogData.value.rowData.version,
|
|
||||||
from: 'remote',
|
|
||||||
address: dialogData.value.rowData.address,
|
|
||||||
port: dialogData.value.rowData.port,
|
|
||||||
username: dialogData.value.rowData.username,
|
|
||||||
password: dialogData.value.rowData.password,
|
|
||||||
description: dialogData.value.rowData.description,
|
|
||||||
};
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
if (operation === 'check') {
|
if (operation === 'check') {
|
||||||
await checkDatabase(param)
|
await checkDatabase(dialogData.value.rowData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
@ -148,7 +157,7 @@ const onSubmit = async (formEl: FormInstance | undefined, operation: string) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (operation === 'create') {
|
if (operation === 'create') {
|
||||||
await addDatabase(param)
|
await addDatabase(dialogData.value.rowData)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
@ -160,7 +169,7 @@ const onSubmit = async (formEl: FormInstance | undefined, operation: string) =>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (operation === 'edit') {
|
if (operation === 'edit') {
|
||||||
await editDatabase(param)
|
await editDatabase(dialogData.value.rowData)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user