1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-03-14 01:34:47 +08:00

feat: 实现远程数据库改密、授权功能

This commit is contained in:
ssongliu 2023-07-21 18:28:45 +08:00 committed by ssongliu
parent cb7351a9fb
commit 7f79f5f031
14 changed files with 94 additions and 28 deletions

View File

@ -68,7 +68,11 @@ func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
// @Security ApiKeyAuth
// @Router /databases/remote/list/:type [get]
func (b *BaseApi) ListRemoteDB(c *gin.Context) {
dbType := c.Query("type")
dbType, err := helper.GetStrParamByKey(c, "type")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
list, err := remoteDBService.List(dbType)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)

View File

@ -6,6 +6,7 @@ type MysqlDBInfo struct {
ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"`
Name string `json:"name"`
From string `json:"from"`
Format string `json:"format"`
Username string `json:"username"`
Password string `json:"password"`

View File

@ -122,10 +122,15 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
if err != nil {
return nil, err
}
defer cli.Close()
if err := cli.Create(client.CreateInfo{
Name: req.Name,
Format: req.Format,
Version: version,
Name: req.Name,
Format: req.Format,
Username: req.Username,
Password: req.Password,
Permission: req.Permission,
Version: version,
Timeout: 300,
}); err != nil {
return nil, err
}
@ -168,6 +173,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
if err != nil {
return err
}
defer cli.Close()
db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
if err != nil && !req.ForceDelete {
return err
@ -216,6 +222,7 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
if err != nil {
return err
}
defer cli.Close()
var (
mysqlData model.DatabaseMysql
passwordInfo client.PasswordChangeInfo
@ -278,6 +285,7 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
if err != nil {
return err
}
defer cli.Close()
var (
mysqlData model.DatabaseMysql
accessInfo client.AccessChangeInfo
@ -293,6 +301,7 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
}
accessInfo.Name = mysqlData.Name
accessInfo.Username = mysqlData.Username
accessInfo.Password = mysqlData.Password
accessInfo.OldPermission = mysqlData.Permission
} else {
accessInfo.Username = "root"
@ -544,14 +553,17 @@ func loadClientByID(id uint) (mysql.MysqlClient, string, error) {
version string
err error
)
dbInfo.From = "local"
if id != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(id))
if err != nil {
return nil, "", err
}
dbInfo.From = mysqlData.From
}
if mysqlData.From != "local" {
if dbInfo.From != "local" {
databaseItem, err := remoteDBRepo.Get(commonRepo.WithByName(mysqlData.From))
if err != nil {
return nil, "", err

View File

@ -41,7 +41,7 @@ func (u *RemoteDBService) SearchWithPage(search dto.RemoteDBSearch) (int64, inte
}
func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType), remoteDBRepo.WithoutByFrom("local"))
dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType))
var datas []dto.RemoteDBOption
for _, db := range dbs {
var item dto.RemoteDBOption

View File

@ -437,7 +437,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
}
}
if snap.InterruptStep == "UpdateLiveRestore" {
_, _ = cmd.Exec("systemctl restart dockere")
_, _ = cmd.Exec("systemctl restart docker")
return
}

View File

@ -42,7 +42,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
cmdRouter.POST("/remote", baseApi.CreateRemoteDB)
cmdRouter.POST("/remote/list/:type", baseApi.ListRemoteDB)
cmdRouter.GET("/remote/list/:type", baseApi.ListRemoteDB)
cmdRouter.POST("/remote/update", baseApi.UpdateRemoteDB)
cmdRouter.POST("/remote/search", baseApi.SearchRemoteDB)
cmdRouter.POST("/remote/del", baseApi.DeleteRemoteDB)

View File

@ -2,7 +2,6 @@ package mysql
import (
"database/sql"
"errors"
"fmt"
"github.com/1Panel-dev/1Panel/backend/buserr"
@ -22,23 +21,21 @@ type MysqlClient interface {
}
func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
if conn.From == "remote" {
connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
db, err := sql.Open("mysql", connArgs)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
return nil, err
}
return client.NewRemote(db), nil
}
if conn.From == "local" {
if cmd.CheckIllegal(conn.Address, conn.Username, conn.Password) {
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), nil
}
return nil, errors.New("no such type")
connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
db, err := sql.Open("mysql", connArgs)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
return nil, err
}
return client.NewRemote(db), nil
}

View File

@ -1,7 +1,7 @@
package client
type DBInfo struct {
From string `json:"from"` // local remote
From string `json:"from"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"userName"`
@ -45,6 +45,7 @@ type AccessChangeInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Username string `json:"userName"`
Password string `json:"password"`
OldPermission string `json:"oldPermission"`
Permission string `json:"permission"`

View File

@ -31,7 +31,7 @@ func (r *Local) Create(info CreateInfo) error {
return err
}
if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
if err := r.CreateUser(info); err != nil {
return err
}
@ -185,7 +185,14 @@ func (r *Local) ChangeAccess(info AccessChangeInfo) error {
return nil
}
}
if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
if err := r.CreateUser(CreateInfo{
Name: info.Name,
Version: info.Version,
Username: info.Username,
Password: info.Password,
Permission: info.Permission,
Timeout: info.Timeout,
}); err != nil {
return err
}
if err := r.ExecSQL("flush privileges", 300); err != nil {

View File

@ -29,7 +29,7 @@ func (r *Remote) Create(info CreateInfo) error {
return err
}
if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
if err := r.CreateUser(info); err != nil {
return err
}
@ -183,7 +183,14 @@ func (r *Remote) ChangeAccess(info AccessChangeInfo) error {
return nil
}
}
if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
if err := r.CreateUser(CreateInfo{
Name: info.Name,
Version: info.Version,
Username: info.Username,
Password: info.Password,
Permission: info.Permission,
Timeout: info.Timeout,
}); err != nil {
return err
}
if err := r.ExecSQL("flush privileges", 300); err != nil {

View File

@ -9,6 +9,7 @@ export namespace Database {
id: number;
createdAt: Date;
name: string;
from: string;
format: string;
username: string;
password: string;

View File

@ -45,6 +45,18 @@
/>
<span class="input-help">{{ $t('database.remoteHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-select v-model="form.from">
<el-option
v-for="(item, index) in dbOptions"
:key="index"
:value="item.name"
:label="loadLabel(item)"
></el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="form.description" />
</el-form-item>
@ -71,15 +83,17 @@ import { reactive, ref } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { addMysqlDB } from '@/api/modules/database';
import { addMysqlDB, listRemoteDBs } from '@/api/modules/database';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { MsgSuccess } from '@/utils/message';
import { getRandomStr } from '@/utils/util';
const loading = ref();
const dbOptions = ref();
const createVisiable = ref(false);
const form = reactive({
name: '',
from: 'local',
mysqlName: '',
format: '',
username: '',
@ -110,12 +124,22 @@ const acceptParams = (params: DialogProps): void => {
form.permissionIPs = '';
form.description = '';
random();
loadDBOptions();
createVisiable.value = true;
};
const handleClose = () => {
createVisiable.value = false;
};
const loadDBOptions = async () => {
const res = await listRemoteDBs('mysql');
dbOptions.value = res.data;
};
function loadLabel(item: any) {
return (item.name === 'local' ? i18n.global.t('database.localDB') : item.name) + '(' + item.address + ')';
}
const random = async () => {
form.password = getRandomStr(16);
};

View File

@ -49,6 +49,11 @@
:class="{ mask: mysqlStatus != 'Running' }"
>
<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.password')" prop="password">
<template #default="{ row }">
@ -310,6 +315,7 @@ const buttons = [
click: (row: Database.MysqlDBInfo) => {
let param = {
id: row.id,
from: row.from,
mysqlName: row.name,
operation: 'password',
username: row.username,
@ -323,6 +329,7 @@ const buttons = [
click: (row: Database.MysqlDBInfo) => {
let param = {
id: row.id,
from: row.from,
mysqlName: row.name,
operation: 'privilege',
privilege: '',

View File

@ -81,6 +81,7 @@ const changeFormRef = ref<FormInstance>();
const title = ref();
const changeForm = reactive({
id: 0,
from: '',
mysqlName: '',
userName: '',
password: '',
@ -93,6 +94,7 @@ const confirmDialogRef = ref();
interface DialogProps {
id: number;
from: string;
mysqlName: string;
username: string;
password: string;
@ -107,6 +109,7 @@ const acceptParams = (params: DialogProps): void => {
? i18n.global.t('database.changePassword')
: i18n.global.t('database.permission');
changeForm.id = params.id;
changeForm.from = params.from === 'local' ? 'local' : 'remote';
changeForm.mysqlName = params.mysqlName;
changeForm.userName = params.username;
changeForm.password = params.password;
@ -128,6 +131,7 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
if (!valid) return;
let param = {
id: changeForm.id,
from: changeForm.from,
value: '',
};
if (changeForm.operation === 'password') {
@ -177,6 +181,7 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
const onSubmit = async () => {
let param = {
id: changeForm.id,
from: changeForm.from,
value: changeForm.password,
};
loading.value = true;