feat: 远程数据库支持添加 mariadb (#2139)

This commit is contained in:
ssongliu 2023-09-01 12:28:12 +08:00 committed by GitHub
parent 66c824a841
commit 149d44dbbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 55 additions and 48 deletions

View file

@ -244,6 +244,7 @@ type DatabaseInfo struct {
CreatedAt time.Time `json:"createdAt"`
Name string `json:"name" validate:"max=256"`
From string `json:"from"`
Type string `json:"type"`
Version string `json:"version"`
Address string `json:"address"`
Port uint `json:"port"`
@ -263,7 +264,7 @@ type DatabaseOption struct {
type DatabaseCreate struct {
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"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`

View file

@ -2,6 +2,8 @@ package repo
import (
"context"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
@ -18,9 +20,8 @@ type IDatabaseRepo interface {
Get(opts ...DBOption) (model.Database, error)
WithByFrom(from string) DBOption
WithoutByFrom(from string) DBOption
WithByMysqlList() DBOption
WithAppInstallID(appInstallID uint) DBOption
WithType(dbType string) DBOption
WithTypeList(dbType string) DBOption
}
func NewIDatabaseRepo() IDatabaseRepo {
@ -59,12 +60,6 @@ func (d *DatabaseRepo) GetList(opts ...DBOption) ([]model.Database, error) {
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 {
return func(g *gorm.DB) *gorm.DB {
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 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
}
}

View file

@ -428,7 +428,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
var res []response.AppService
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 {
return res, nil
}

View file

@ -4,7 +4,6 @@ import (
"context"
"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/utils/mysql"
"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) {
total, dbs, err := databaseRepo.Page(search.Page, search.PageSize,
commonRepo.WithByType(search.Type),
databaseRepo.WithTypeList(search.Type),
commonRepo.WithLikeName(search.Info),
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) {
var opts []repo.DBOption
if dbType == "mysql" {
opts = append(opts, databaseRepo.WithByMysqlList())
} else {
opts = append(opts, commonRepo.WithByType(dbType))
}
dbs, err := databaseRepo.GetList(opts...)
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
var datas []dto.DatabaseOption
for _, db := range dbs {
var item dto.DatabaseOption

View file

@ -147,7 +147,7 @@ func (r *Local) ChangePassword(info PasswordChangeInfo) error {
for _, user := range userlist {
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") {
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 {
return err

View file

@ -152,7 +152,7 @@ func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
for _, user := range userlist {
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") {
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 {
return err

View file

@ -354,7 +354,7 @@ const message = {
localDB: 'Local DB',
address: 'DB address',
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.',
selectFile: 'Select file',

View file

@ -346,7 +346,7 @@ const message = {
localDB: '本地數據庫',
address: '數據庫地址',
version: '數據庫版本',
versionHelper: '當前僅支持 5.6 5.7 8.0 三個版本',
versionHelper: '當前僅支持 {0} 三個版本',
userHelper: 'root 用戶或者擁有 root 權限的數據庫用戶',
selectFile: '選擇文件',

View file

@ -346,7 +346,7 @@ const message = {
localDB: '本地数据库',
address: '数据库地址',
version: '数据库版本',
versionHelper: '当前仅支持 5.6 5.7 8.0 三个版本',
versionHelper: '当前仅支持 {0} 版本',
userHelper: 'root 用户或者拥有 root 权限的数据库用户',
selectFile: '选择文件',

View file

@ -386,7 +386,7 @@ const checkExist = (data: App.CheckInstalled) => {
};
const loadDBOptions = async () => {
const res = await listDatabases('mysql');
const res = await listDatabases('mysql,mariadb');
let datas = res.data || [];
dbOptionsLocal.value = [];
dbOptionsRemote.value = [];

View file

@ -121,7 +121,7 @@ const search = async (column?: any) => {
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
info: searchName.value,
type: 'mysql',
type: 'mysql,mariadb',
orderBy: paginationConfig.orderBy,
order: paginationConfig.order,
};

View file

@ -19,13 +19,29 @@
/>
<el-tag v-else>{{ dialogData.rowData!.name }}</el-tag>
</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-select @change="isOK = false" v-model="dialogData.rowData!.version">
<el-option value="5.6" label="5.6" />
<el-option value="5.7" label="5.7" />
<el-option value="8.0" label="8.0" />
<div v-if="dialogData.rowData!.type === 'mysql'">
<el-option value="5.6" label="5.6" />
<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>
<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 :label="$t('database.address')" prop="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>;
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) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let param = {
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,
};
dialogData.value.rowData.from = 'remote';
loading.value = true;
if (operation === 'check') {
await checkDatabase(param)
await checkDatabase(dialogData.value.rowData)
.then((res) => {
loading.value = false;
if (res.data) {
@ -148,7 +157,7 @@ const onSubmit = async (formEl: FormInstance | undefined, operation: string) =>
}
if (operation === 'create') {
await addDatabase(param)
await addDatabase(dialogData.value.rowData)
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
@ -160,7 +169,7 @@ const onSubmit = async (formEl: FormInstance | undefined, operation: string) =>
});
}
if (operation === 'edit') {
await editDatabase(param)
await editDatabase(dialogData.value.rowData)
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));