feat: 增加 redis 状态获取、配置获取等接口

pull/34/head
ssongliu 2022-10-31 23:52:39 +08:00 committed by ssongliu
parent 37dee0dd81
commit bc5b269691
18 changed files with 927 additions and 198 deletions

View File

@ -81,13 +81,13 @@ func (b *BaseApi) SearchMysql(c *gin.Context) {
}
func (b *BaseApi) ListDBNameByVersion(c *gin.Context) {
version, ok := c.Params.Get("version")
name, ok := c.Params.Get("name")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error version in path"))
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error name in path"))
return
}
list, err := mysqlService.ListDBByVersion(version)
list, err := mysqlService.ListDBByVersion(name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@ -155,13 +155,13 @@ func (b *BaseApi) DeleteMysql(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
version, ok := c.Params.Get("version")
name, ok := c.Params.Get("name")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error version in path"))
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error name in path"))
return
}
if err := mysqlService.Delete(version, req.Ids); err != nil {
if err := mysqlService.Delete(name, req.Ids); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@ -179,13 +179,13 @@ func (b *BaseApi) LoadVersions(c *gin.Context) {
}
func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
version, ok := c.Params.Get("version")
name, ok := c.Params.Get("name")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error version in path"))
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error name in path"))
return
}
data, err := mysqlService.LoadBaseInfo(version)
data, err := mysqlService.LoadBaseInfo(name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@ -195,13 +195,13 @@ func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
}
func (b *BaseApi) LoadStatus(c *gin.Context) {
version, ok := c.Params.Get("version")
name, ok := c.Params.Get("name")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error version in path"))
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error name in path"))
return
}
data, err := mysqlService.LoadStatus(version)
data, err := mysqlService.LoadStatus(name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@ -211,12 +211,12 @@ func (b *BaseApi) LoadStatus(c *gin.Context) {
}
func (b *BaseApi) LoadVariables(c *gin.Context) {
version, ok := c.Params.Get("version")
name, ok := c.Params.Get("name")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error version in path"))
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error name in path"))
return
}
data, err := mysqlService.LoadVariables(version)
data, err := mysqlService.LoadVariables(name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return

View File

@ -1,9 +1,6 @@
package v1
import (
"errors"
"strconv"
"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"
@ -65,19 +62,84 @@ func (b *BaseApi) DeleteRedis(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) CleanRedis(c *gin.Context) {
db, ok := c.Params.Get("db")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error db in path"))
func (b *BaseApi) LoadRedisRunningVersion(c *gin.Context) {
list, err := redisService.LoadRedisRunningVersion()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
dbNum, err := strconv.Atoi(db)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error db in path"))
helper.SuccessWithData(c, list)
}
func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
var req dto.RedisBaseReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := redisService.CleanAll(dbNum); err != nil {
data, err := redisService.LoadState(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
func (b *BaseApi) LoadRedisConf(c *gin.Context) {
var req dto.RedisBaseReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := redisService.LoadConf(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
func (b *BaseApi) CleanRedis(c *gin.Context) {
var req dto.RedisBaseReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := redisService.CleanAll(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) UpdateRedisConf(c *gin.Context) {
var req dto.RedisConfUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := redisService.UpdateConf(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@ -16,7 +16,7 @@ type MysqlDBInfo struct {
type MysqlDBCreate struct {
Name string `json:"name" validate:"required"`
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
MysqlName string `json:"mysqlName" validate:"required"`
Format string `json:"format" validate:"required,oneof=utf8mb4 utf-8 gbk big5"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
@ -82,7 +82,7 @@ type MysqlVariables struct {
}
type MysqlVariablesUpdate struct {
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
MysqlName string `json:"mysqlName" validate:"required"`
KeyBufferSize int64 `json:"key_buffer_size" validate:"required"`
QueryCacheSize int64 `json:"query_cache_size" validate:"required"`
TmpTableSize int64 `json:"tmp_table_size" validate:"required"`
@ -102,7 +102,7 @@ type MysqlVariablesUpdate struct {
type ChangeDBInfo struct {
ID uint `json:"id"`
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
MysqlName string `json:"mysqlName" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=password privilege"`
Value string `json:"value" validate:"required"`
}
@ -112,26 +112,27 @@ type DBBaseInfo struct {
Port int64 `json:"port"`
Password string `json:"password"`
RemoteConn bool `json:"remoteConn"`
MysqlKey string `json:"mysqlKey"`
}
type SearchDBWithPage struct {
PageInfo
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
MysqlName string `json:"mysqlName" validate:"required"`
}
type SearchBackupsWithPage struct {
PageInfo
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
DBName string `json:"dbName" validate:"required"`
MysqlName string `json:"mysqlName" validate:"required"`
DBName string `json:"dbName" validate:"required"`
}
type BackupDB struct {
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
DBName string `json:"dbName" validate:"required"`
MysqlName string `json:"mysqlName" validate:"required"`
DBName string `json:"dbName" validate:"required"`
}
type RecoverDB struct {
Version string `json:"version" validate:"required,oneof=mysql5.7 mysql8.0"`
MysqlName string `json:"mysqlName" validate:"required"`
DBName string `json:"dbName" validate:"required"`
BackupName string `json:"backupName" validate:"required"`
}
@ -139,7 +140,8 @@ type RecoverDB struct {
// redis
type SearchRedisWithPage struct {
PageInfo
DB int `json:"db" validate:"required"`
RedisName string `json:"redisName" validate:"required"`
DB int `json:"db" validate:"required"`
}
type RedisData struct {
@ -151,6 +153,7 @@ type RedisData struct {
}
type RedisDataSet struct {
RedisName string `json:"redisName" validate:"required"`
DB int `json:"db"`
Key string `json:"key" validate:"required"`
Value string `json:"value" validate:"required"`
@ -158,6 +161,48 @@ type RedisDataSet struct {
}
type RedisDelBatch struct {
DB int `json:"db" validate:"required"`
Names []string `json:"names" validate:"required"`
RedisName string `json:"redisName" validate:"required"`
DB int `json:"db" validate:"required"`
Names []string `json:"names" validate:"required"`
}
type RedisBaseReq struct {
RedisName string `json:"redisName" validate:"required"`
DB int `json:"db"`
}
type RedisConfUpdate struct {
RedisName string `json:"redisName" validate:"required"`
DB int `json:"db"`
ParamName string `json:"paramName" validate:"required"`
Value string `json:"value"`
}
type RedisConf struct {
Timeout string `json:"timeout"`
Maxclients string `json:"maxclients"`
Databases string `json:"databases"`
Requirepass string `json:"requirepass"`
Maxmemory string `json:"maxmemory"`
Dir string `json:"dir"`
Appendonly string `json:"appendonly"`
Appendfsync string `json:"appendfsync"`
Save string `json:"save"`
}
type RedisStatus struct {
TcpPort string `json:"tcp_port"`
UptimeInDays string `json:"uptime_in_days"`
ConnectedClients string `json:"connected_clients"`
UsedMemory string `json:"used_memory"`
UsedMemory_rss string `json:"used_memory_rss"`
UsedMemory_peak string `json:"used_memory_peak"`
MemFragmentationRatio string `json:"mem_fragmentation_ratio"`
TotalConnectionsReceived string `json:"total_connections_received"`
TotalCommandsProcessed string `json:"total_commands_processed"`
InstantaneousOpsPerSec string `json:"instantaneous_ops_per_sec"`
KeyspaceHits string `json:"keyspace_hits"`
KeyspaceMisses string `json:"keyspace_misses"`
LatestForkUsec string `json:"latest_fork_usec"`
}

View File

@ -3,7 +3,7 @@ package model
type DatabaseMysql struct {
BaseModel
Name string `json:"name" gorm:"type:varchar(256);not null"`
Version string `json:"version" 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"`
Username string `json:"username" gorm:"type:varchar(256);not null"`
Password string `json:"password" gorm:"type:varchar(256);not null"`

View File

@ -13,14 +13,15 @@ type MysqlRepo struct{}
type IMysqlRepo interface {
Get(opts ...DBOption) (model.DatabaseMysql, error)
WithByVersion(version string) DBOption
WithByMysqlName(mysqlName string) DBOption
List(opts ...DBOption) ([]model.DatabaseMysql, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.DatabaseMysql, error)
Create(mysql *model.DatabaseMysql) error
Delete(opts ...DBOption) error
Update(id uint, vars map[string]interface{}) error
LoadRunningVersion() ([]string, error)
LoadBaseInfoByKey(key string) (*RootInfo, error)
LoadRunningVersion(keys []string) ([]string, error)
LoadBaseInfoByName(name string) (*RootInfo, error)
LoadRedisBaseInfoByName(name string) (*RootInfo, error)
UpdateMysqlConf(id uint, vars map[string]interface{}) error
}
@ -60,21 +61,21 @@ func (u *MysqlRepo) Page(page, size int, opts ...DBOption) (int64, []model.Datab
return count, users, err
}
func (u *MysqlRepo) LoadRunningVersion() ([]string, error) {
func (u *MysqlRepo) LoadRunningVersion(keys []string) ([]string, error) {
var (
apps []model.App
appInstall model.AppInstall
appInstall []model.AppInstall
results []string
)
if err := global.DB.Where("name = ? OR name = ?", "Mysql5.7", "Mysql8.0").Find(&apps).Error; err != nil {
if err := global.DB.Where("name in (?)", keys).Find(&apps).Error; err != nil {
return nil, err
}
for _, app := range apps {
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil && err != gorm.ErrRecordNotFound {
if err := global.DB.Where("app_id = ?", app.ID).Find(&appInstall).Error; err != nil {
return nil, err
}
if appInstall.ID != 0 {
results = append(results, app.Key)
for _, item := range appInstall {
results = append(results, item.Name)
}
}
return results, nil
@ -88,18 +89,56 @@ type RootInfo struct {
ContainerName string `json:"containerName"`
Param string `json:"param"`
Env string `json:"env"`
Key string `json:"key"`
}
func (u *MysqlRepo) LoadBaseInfoByKey(key string) (*RootInfo, error) {
func (u *MysqlRepo) LoadBaseInfoByName(name string) (*RootInfo, error) {
var (
app model.App
appInstall model.AppInstall
info RootInfo
)
if err := global.DB.Where("key = ?", key).First(&app).Error; err != nil {
if err := global.DB.Where("name = ?", name).First(&appInstall).Error; err != nil {
return nil, err
}
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
if err := global.DB.Where("id = ?", appInstall.AppId).First(&app).Error; err != nil {
return nil, err
}
envMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(appInstall.Env), &envMap); err != nil {
return nil, err
}
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
if ok {
info.Password = password
} else {
return nil, errors.New("error password in db")
}
port, ok := envMap["PANEL_APP_PORT_HTTP"].(float64)
if ok {
info.Port = int64(port)
} else {
return nil, errors.New("error port in db")
}
info.ID = appInstall.ID
info.Key = app.Key
info.ContainerName = appInstall.ContainerName
info.Name = appInstall.Name
info.Env = appInstall.Env
info.Param = appInstall.Param
return &info, nil
}
func (u *MysqlRepo) LoadRedisBaseInfoByName(name string) (*RootInfo, error) {
var (
app model.App
appInstall model.AppInstall
info RootInfo
)
if err := global.DB.Where("key = ?", "redis").First(&app).Error; err != nil {
return nil, err
}
if err := global.DB.Where("app_id = ? AND name = ?", app.ID, name).First(&appInstall).Error; err != nil {
return nil, err
}
envMap := make(map[string]interface{})
@ -149,8 +188,8 @@ func (u *MysqlRepo) UpdateMysqlConf(id uint, vars map[string]interface{}) error
return nil
}
func (c *MysqlRepo) WithByVersion(version string) DBOption {
func (c *MysqlRepo) WithByMysqlName(mysqlName string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("version = ?", version)
return g.Where("mysql_name = ?", mysqlName)
}
}

View File

@ -23,7 +23,7 @@ type MysqlService struct{}
type IMysqlService interface {
SearchWithPage(search dto.SearchDBWithPage) (int64, interface{}, error)
ListDBByVersion(version string) ([]string, error)
ListDBByVersion(name string) ([]string, error)
SearchBackupsWithPage(search dto.SearchBackupsWithPage) (int64, interface{}, error)
Create(mysqlDto dto.MysqlDBCreate) error
ChangeInfo(info dto.ChangeDBInfo) error
@ -32,11 +32,11 @@ type IMysqlService interface {
Backup(db dto.BackupDB) error
Recover(db dto.RecoverDB) error
Delete(version string, ids []uint) error
LoadStatus(version string) (*dto.MysqlStatus, error)
LoadVariables(version string) (*dto.MysqlVariables, error)
Delete(name string, ids []uint) error
LoadStatus(name string) (*dto.MysqlStatus, error)
LoadVariables(vernamesion string) (*dto.MysqlVariables, error)
LoadRunningVersion() ([]string, error)
LoadBaseInfo(version string) (*dto.DBBaseInfo, error)
LoadBaseInfo(name string) (*dto.DBBaseInfo, error)
}
func NewIMysqlService() IMysqlService {
@ -44,7 +44,7 @@ func NewIMysqlService() IMysqlService {
}
func (u *MysqlService) SearchWithPage(search dto.SearchDBWithPage) (int64, interface{}, error) {
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, mysqlRepo.WithByVersion(search.Version))
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, mysqlRepo.WithByMysqlName(search.MysqlName))
var dtoMysqls []dto.MysqlDBInfo
for _, mysql := range mysqls {
var item dto.MysqlDBInfo
@ -56,8 +56,8 @@ func (u *MysqlService) SearchWithPage(search dto.SearchDBWithPage) (int64, inter
return total, dtoMysqls, err
}
func (u *MysqlService) ListDBByVersion(version string) ([]string, error) {
mysqls, err := mysqlRepo.List(mysqlRepo.WithByVersion(version))
func (u *MysqlService) ListDBByVersion(name string) ([]string, error) {
mysqls, err := mysqlRepo.List(commonRepo.WithByName(name))
var dbNames []string
for _, mysql := range mysqls {
dbNames = append(dbNames, mysql.Name)
@ -66,7 +66,7 @@ func (u *MysqlService) ListDBByVersion(version string) ([]string, error) {
}
func (u *MysqlService) SearchBackupsWithPage(search dto.SearchBackupsWithPage) (int64, interface{}, error) {
app, err := mysqlRepo.LoadBaseInfoByKey(search.Version)
app, err := mysqlRepo.LoadBaseInfoByName(search.MysqlName)
if err != nil {
return 0, nil, err
}
@ -81,7 +81,7 @@ func (u *MysqlService) SearchBackupsWithPage(search dto.SearchBackupsWithPage) (
}
func (u *MysqlService) LoadRunningVersion() ([]string, error) {
return mysqlRepo.LoadRunningVersion()
return mysqlRepo.LoadRunningVersion([]string{"Mysql5.7", "Mysql8.0"})
}
func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error {
@ -96,7 +96,7 @@ func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
app, err := mysqlRepo.LoadBaseInfoByKey(mysqlDto.Version)
app, err := mysqlRepo.LoadBaseInfoByName(mysqlDto.MysqlName)
if err != nil {
return err
}
@ -108,7 +108,7 @@ func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error {
return err
}
grantStr := fmt.Sprintf("grant all privileges on %s.* to '%s'@'%s'", mysqlDto.Name, mysqlDto.Username, tmpPermission)
if mysqlDto.Version == "5.7.39" {
if app.Key == "mysql5.7" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysqlDto.Password)
}
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
@ -129,16 +129,16 @@ func (u *MysqlService) Backup(db dto.BackupDB) error {
if err != nil {
return err
}
backupDir := fmt.Sprintf("database/%s/%s", db.Version, db.DBName)
backupDir := fmt.Sprintf("database/%s/%s", db.MysqlName, db.DBName)
fileName := fmt.Sprintf("%s_%s.sql.gz", db.DBName, time.Now().Format("20060102150405"))
if err := backupMysql("LOCAL", localDir, backupDir, db.Version, db.DBName, fileName); err != nil {
if err := backupMysql("LOCAL", localDir, backupDir, db.MysqlName, db.DBName, fileName); err != nil {
return err
}
return nil
}
func (u *MysqlService) Recover(db dto.RecoverDB) error {
app, err := mysqlRepo.LoadBaseInfoByKey(db.Version)
app, err := mysqlRepo.LoadBaseInfoByName(db.MysqlName)
if err != nil {
return err
}
@ -162,8 +162,8 @@ func (u *MysqlService) Recover(db dto.RecoverDB) error {
return nil
}
func (u *MysqlService) Delete(version string, ids []uint) error {
app, err := mysqlRepo.LoadBaseInfoByKey(version)
func (u *MysqlService) Delete(name string, ids []uint) error {
app, err := mysqlRepo.LoadBaseInfoByName(name)
if err != nil {
return err
}
@ -198,7 +198,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error {
return err
}
}
app, err := mysqlRepo.LoadBaseInfoByKey(info.Version)
app, err := mysqlRepo.LoadBaseInfoByName(info.MysqlName)
if err != nil {
return err
}
@ -247,7 +247,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error {
return err
}
grantStr := fmt.Sprintf("grant all privileges on %s.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
if mysql.Version == "5.7.39" {
if app.Key == "mysql5.7" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
}
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
@ -266,7 +266,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error {
}
func (u *MysqlService) UpdateVariables(variables dto.MysqlVariablesUpdate) error {
app, err := mysqlRepo.LoadBaseInfoByKey(variables.Version)
app, err := mysqlRepo.LoadBaseInfoByName(variables.MysqlName)
if err != nil {
return err
}
@ -318,15 +318,16 @@ func (u *MysqlService) UpdateVariables(variables dto.MysqlVariablesUpdate) error
return nil
}
func (u *MysqlService) LoadBaseInfo(version string) (*dto.DBBaseInfo, error) {
func (u *MysqlService) LoadBaseInfo(name string) (*dto.DBBaseInfo, error) {
var data dto.DBBaseInfo
app, err := mysqlRepo.LoadBaseInfoByKey(version)
app, err := mysqlRepo.LoadBaseInfoByName(name)
if err != nil {
return nil, err
}
data.Name = app.Name
data.Port = int64(app.Port)
data.Password = app.Password
data.MysqlKey = app.Key
hosts, err := excuteSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
if err != nil {
@ -341,8 +342,8 @@ func (u *MysqlService) LoadBaseInfo(version string) (*dto.DBBaseInfo, error) {
return &data, nil
}
func (u *MysqlService) LoadVariables(version string) (*dto.MysqlVariables, error) {
app, err := mysqlRepo.LoadBaseInfoByKey(version)
func (u *MysqlService) LoadVariables(name string) (*dto.MysqlVariables, error) {
app, err := mysqlRepo.LoadBaseInfoByName(name)
if err != nil {
return nil, err
}
@ -359,8 +360,8 @@ func (u *MysqlService) LoadVariables(version string) (*dto.MysqlVariables, error
return &info, nil
}
func (u *MysqlService) LoadStatus(version string) (*dto.MysqlStatus, error) {
app, err := mysqlRepo.LoadBaseInfoByKey(version)
func (u *MysqlService) LoadStatus(name string) (*dto.MysqlStatus, error) {
app, err := mysqlRepo.LoadBaseInfoByName(name)
if err != nil {
return nil, err
}
@ -443,8 +444,8 @@ func excuteSql(containerName, password, command string) error {
return nil
}
func backupMysql(backupType, baseDir, backupDir, version, dbName, fileName string) error {
app, err := mysqlRepo.LoadBaseInfoByKey(version)
func backupMysql(backupType, baseDir, backupDir, mysqkName, dbName, fileName string) error {
app, err := mysqlRepo.LoadBaseInfoByName(mysqkName)
if err != nil {
return err
}

View File

@ -1,7 +1,9 @@
package service
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@ -15,7 +17,13 @@ type IRedisService interface {
SearchWithPage(search dto.SearchRedisWithPage) (int64, interface{}, error)
Set(setData dto.RedisDataSet) error
Delete(info dto.RedisDelBatch) error
CleanAll(db int) error
UpdateConf(req dto.RedisConfUpdate) error
CleanAll(req dto.RedisBaseReq) error
LoadState(req dto.RedisBaseReq) (*dto.RedisStatus, error)
LoadConf(req dto.RedisBaseReq) (*dto.RedisConf, error)
LoadRedisRunningVersion() ([]string, error)
// Backup(db dto.BackupDB) error
// Recover(db dto.RecoverDB) error
@ -25,16 +33,24 @@ func NewIRedisService() IRedisService {
return &RedisService{}
}
func (u *RedisService) SearchWithPage(search dto.SearchRedisWithPage) (int64, interface{}, error) {
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
func newRedisClient(name string, db int) (*redis.Client, error) {
redisInfo, err := mysqlRepo.LoadRedisBaseInfoByName(name)
if err != nil {
return 0, nil, err
return nil, err
}
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("localhost:%v", redisInfo.Port),
Password: "eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81",
DB: search.DB,
DB: db,
})
return client, nil
}
func (u *RedisService) SearchWithPage(search dto.SearchRedisWithPage) (int64, interface{}, error) {
client, err := newRedisClient(search.RedisName, search.DB)
if err != nil {
return 0, nil, err
}
total, err := client.DbSize().Result()
if err != nil {
return 0, nil, err
@ -72,16 +88,30 @@ func (u *RedisService) SearchWithPage(search dto.SearchRedisWithPage) (int64, in
return total, data, nil
}
func (u *RedisService) Set(setData dto.RedisDataSet) error {
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
func (u *RedisService) LoadRedisRunningVersion() ([]string, error) {
return mysqlRepo.LoadRunningVersion([]string{"redis"})
}
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
client, err := newRedisClient(req.RedisName, 0)
if err != nil {
return err
}
if _, err := client.ConfigSet(req.ParamName, req.Value).Result(); err != nil {
return err
}
if _, err := client.ConfigRewrite().Result(); err != nil {
return err
}
return nil
}
func (u *RedisService) Set(setData dto.RedisDataSet) error {
client, err := newRedisClient(setData.RedisName, setData.DB)
if err != nil {
return err
}
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("localhost:%v", redisInfo.Port),
Password: "eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81",
DB: setData.DB,
})
value, _ := client.Get(setData.Key).Result()
if err != nil {
return err
@ -98,33 +128,78 @@ func (u *RedisService) Set(setData dto.RedisDataSet) error {
}
func (u *RedisService) Delete(req dto.RedisDelBatch) error {
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
client, err := newRedisClient(req.RedisName, req.DB)
if err != nil {
return err
}
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("localhost:%v", redisInfo.Port),
Password: "eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81",
DB: req.DB,
})
if _, err := client.Del(req.Names...).Result(); err != nil {
return err
}
return nil
}
func (u *RedisService) CleanAll(db int) error {
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
func (u *RedisService) CleanAll(req dto.RedisBaseReq) error {
client, err := newRedisClient(req.RedisName, req.DB)
if err != nil {
return err
}
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("localhost:%v", redisInfo.Port),
Password: "eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81",
DB: db,
})
if _, err := client.FlushAll().Result(); err != nil {
return err
}
return nil
}
func (u *RedisService) LoadState(req dto.RedisBaseReq) (*dto.RedisStatus, error) {
client, err := newRedisClient(req.RedisName, req.DB)
if err != nil {
return nil, err
}
stdStr, err := client.Info().Result()
if err != nil {
return nil, err
}
rows := strings.Split(stdStr, "\r\n")
rowMap := make(map[string]string)
for _, v := range rows {
itemRow := strings.Split(v, ":")
if len(itemRow) == 2 {
rowMap[itemRow[0]] = itemRow[1]
}
}
var info dto.RedisStatus
arr, err := json.Marshal(rowMap)
if err != nil {
return nil, err
}
_ = json.Unmarshal(arr, &info)
return &info, nil
}
func (u *RedisService) LoadConf(req dto.RedisBaseReq) (*dto.RedisConf, error) {
client, err := newRedisClient(req.RedisName, req.DB)
if err != nil {
return nil, err
}
var item dto.RedisConf
item.Timeout = configGetStr(client, "timeout")
item.Maxclients = configGetStr(client, "maxclients")
item.Databases = configGetStr(client, "databases")
item.Requirepass = configGetStr(client, "requirepass")
item.Maxmemory = configGetStr(client, "maxmemory")
item.Dir = configGetStr(client, "dir")
item.Appendonly = configGetStr(client, "appendonly")
item.Appendfsync = configGetStr(client, "appendfsync")
item.Save = configGetStr(client, "save")
return &item, nil
}
func configGetStr(client *redis.Client, param string) string {
item, _ := client.ConfigGet(param).Result()
if len(item) == 2 {
if value, ok := item[1].(string); ok {
return value
}
}
return ""
}

View File

@ -3,7 +3,6 @@ package service
import (
"fmt"
"testing"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/go-redis/redis"
@ -15,48 +14,31 @@ func TestMysql(t *testing.T) {
Password: "eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81",
DB: 0,
})
// fmt.Println(rdb.Get("dqwas"))
client.Set("omg", "111", 10*time.Minute)
client.Set("omg1", "111", 10*time.Minute)
client.Set("omg2", "111", 10*time.Minute)
client.Set("omg3", "111", 10*time.Minute)
client.Set("omg4", "111", 10*time.Minute)
client.Set("omg5", "111", 10*time.Minute)
client.Set("omg6", "111", 10*time.Minute)
client.Set("omg7", "111", 10*time.Minute)
client.Set("omg8", "111", 10*time.Minute)
client.Set("omg9", "111", 10*time.Minute)
keys, _, err := client.Scan(0, "*", 5).Result()
if err != nil {
panic(err)
var item dto.RedisConf
dir, _ := client.ConfigGet("dir").Result()
if len(dir) == 2 {
if value, ok := dir[1].(string); ok {
item.Dir = value
}
}
var data []dto.RedisData
for _, key := range keys {
var dataItem dto.RedisData
dataItem.Key = key
value, err := client.Get(key).Result()
if err != nil {
fmt.Println(err)
appendonly, _ := client.ConfigGet("appendonly").Result()
if len(appendonly) == 2 {
if value, ok := appendonly[1].(string); ok {
item.Appendonly = value
}
dataItem.Value = value
typeVal, err := client.Type(key).Result()
if err != nil {
fmt.Println(err)
}
dataItem.Type = typeVal
length, err := client.StrLen(key).Result()
if err != nil {
fmt.Println(err)
}
dataItem.Length = length
ttl, err := client.TTL(key).Result()
if err != nil {
fmt.Println(err)
}
dataItem.Expiration = int64(ttl / 1000000000)
data = append(data, dataItem)
}
fmt.Println(data)
appendfsync, _ := client.ConfigGet("appendfsync").Result()
if len(appendfsync) == 2 {
if value, ok := appendfsync[1].(string); ok {
item.Appendfsync = value
}
}
save, _ := client.ConfigGet("save").Result()
if len(save) == 2 {
if value, ok := save[1].(string); ok {
item.Save = value
}
}
fmt.Println(item)
}

View File

@ -29,15 +29,19 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
withRecordRouter.POST("/del", baseApi.DeleteMysql)
withRecordRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
cmdRouter.POST("/search", baseApi.SearchMysql)
cmdRouter.GET("/variables/:version", baseApi.LoadVariables)
cmdRouter.GET("/status/:version", baseApi.LoadStatus)
cmdRouter.GET("/baseinfo/:version", baseApi.LoadBaseinfo)
cmdRouter.GET("/variables/:name", baseApi.LoadVariables)
cmdRouter.GET("/status/:name", baseApi.LoadStatus)
cmdRouter.GET("/baseinfo/:name", baseApi.LoadBaseinfo)
cmdRouter.GET("/versions", baseApi.LoadVersions)
cmdRouter.GET("/dbs/:version", baseApi.ListDBNameByVersion)
cmdRouter.GET("/dbs/:name", baseApi.ListDBNameByVersion)
cmdRouter.POST("/redis/search", baseApi.SearchRedis)
withRecordRouter.POST("/redis", baseApi.SetRedis)
withRecordRouter.POST("/redis/del", baseApi.DeleteRedis)
withRecordRouter.POST("/redis/clean/:db", baseApi.CleanRedis)
withRecordRouter.POST("/redis/cleanall", baseApi.CleanRedis)
withRecordRouter.POST("/redis/status", baseApi.LoadRedisStatus)
withRecordRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf)
withRecordRouter.POST("/redis/conf", baseApi.LoadRedisConf)
cmdRouter.GET("/redis/versions", baseApi.LoadRedisRunningVersion)
}
}

View File

@ -2,18 +2,18 @@ import { ReqPage } from '.';
export namespace Database {
export interface Search extends ReqPage {
version: string;
mysqlName: string;
}
export interface SearchBackupRecord extends ReqPage {
version: string;
mysqlName: string;
dbName: string;
}
export interface Backup {
version: string;
mysqlName: string;
dbName: string;
}
export interface Recover {
version: string;
mysqlName: string;
dbName: string;
backupName: string;
}
@ -32,10 +32,11 @@ export namespace Database {
port: number;
password: string;
remoteConn: boolean;
mysqlKey: string;
}
export interface MysqlDBCreate {
name: string;
version: string;
mysqlName: string;
format: string;
username: string;
password: string;
@ -43,7 +44,7 @@ export namespace Database {
description: string;
}
export interface MysqlVariables {
version: string;
mysqlName: string;
binlog_cache_size: number;
innodb_buffer_pool_size: number;
innodb_log_buffer_size: number;
@ -98,16 +99,29 @@ export namespace Database {
}
export interface ChangeInfo {
id: number;
version: string;
mysqlName: string;
operation: string;
value: string;
}
// redis
export interface SearchRedisWithPage extends ReqPage {
redisName: string;
db: number;
}
export interface RedisBaseReq {
redisName: string;
db: number;
}
export interface RedisConfUpdate {
redisName: string;
db: number;
paramName: string;
value: string;
}
export interface RedisData {
redisName: string;
db: number;
key: string;
value: string;
type: string;
@ -115,14 +129,42 @@ export namespace Database {
expiration: number;
}
export interface RedisDataSet {
redisName: string;
db: number;
key: string;
value: string;
expiration: number;
}
export interface RedisDelBatch {
redisName: string;
db: number;
names: Array<string>;
}
export interface RedisStatus {
tcp_port: string;
uptime_in_days: string;
connected_clients: string;
used_memory: string;
used_memory_rss: string;
used_memory_peak: string;
mem_fragmentation_ratio: string;
total_connections_received: string;
total_commands_processed: string;
instantaneous_ops_per_sec: string;
keyspace_hits: string;
keyspace_misses: string;
latest_fork_usec: string;
}
export interface RedisConf {
timeout: number;
maxclients: number;
databases: number;
requirepass: string;
maxmemory: number;
dir: string;
appendonly: string;
appendfsync: string;
save: string;
}
}

View File

@ -56,6 +56,18 @@ export const setRedis = (params: Database.RedisDataSet) => {
export const deleteRedisKey = (params: Database.RedisDelBatch) => {
return http.post(`/databases/redis/del`, params);
};
export const cleanRedisKey = (db: number) => {
return http.post(`/databases/redis/clean/${db}`);
export const cleanRedisKey = (params: Database.RedisBaseReq) => {
return http.post(`/databases/redis/clean`, params);
};
export const loadRedisStatus = (params: Database.RedisBaseReq) => {
return http.post<Database.RedisStatus>(`/databases/redis/status`, params);
};
export const loadRedisConf = (params: Database.RedisBaseReq) => {
return http.post<Database.RedisConf>(`/databases/redis/conf`, params);
};
export const updateRedisConf = (params: Database.RedisConfUpdate) => {
return http.post(`/databases/redis/conf/update`, params);
};
export const loadRedisVersions = () => {
return http.get(`/databases/redis/versions`);
};

View File

@ -228,6 +228,36 @@ export default {
expirationHelper: ' 0 ',
forever: '',
second: '秒',
timeout: '',
timeoutHelper: '0',
maxclients: '',
requirepass: '',
requirepassHelper: '',
databases: '',
maxmemory: '使',
maxmemoryHelper: '0 ',
tcpPort: '',
uptimeInDays: '',
connectedClients: '',
usedMemory: 'Redis ',
usedMemoryRss: 'Redis ',
memFragmentationRatio: '',
totalConnectionsReceived: '',
totalCommandsProcessed: '',
instantaneousOpsPerSec: '',
keyspaceHits: '',
keyspaceMisses: '',
hit: '',
latestForkUsec: ' fork() ',
persistence: '',
persistenceDir: '',
persistenceDirHelper: ' redis_cache redis ',
aofPersistence: 'AOF ',
rdbPersistence: 'RDB ',
drbHelper1: ',',
drbHelper2: '',
drbHelper3: 'RDB',
},
container: {
operatorHelper: ' {0} ',

View File

@ -52,14 +52,14 @@ const paginationConfig = reactive({
});
const backupVisiable = ref(false);
const version = ref();
const mysqlName = ref();
const dbName = ref();
interface DialogProps {
version: string;
mysqlName: string;
dbName: string;
}
const acceptParams = (params: DialogProps): void => {
version.value = params.version;
mysqlName.value = params.mysqlName;
dbName.value = params.dbName;
backupVisiable.value = true;
search();
@ -69,7 +69,7 @@ const search = async () => {
let params = {
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
version: version.value,
mysqlName: mysqlName.value,
dbName: dbName.value,
};
const res = await searchBackupRecords(params);
@ -79,7 +79,7 @@ const search = async () => {
const onBackup = async () => {
let params = {
version: version.value,
mysqlName: mysqlName.value,
dbName: dbName.value,
};
await backup(params);
@ -89,7 +89,7 @@ const onBackup = async () => {
const onRecover = async (row: Backup.RecordInfo) => {
let params = {
version: version.value,
mysqlName: mysqlName.value,
dbName: dbName.value,
backupName: row.fileDir + row.fileName,
};

View File

@ -60,7 +60,7 @@ import { addMysqlDB } from '@/api/modules/database';
const createVisiable = ref(false);
const form = reactive({
name: '',
version: '',
mysqlName: '',
format: '',
username: '',
password: '',
@ -79,11 +79,11 @@ type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
interface DialogProps {
version: string;
mysqlName: string;
}
const acceptParams = (params: DialogProps): void => {
form.name = '';
form.version = params.version;
form.mysqlName = params.mysqlName;
form.format = 'utf8mb4';
form.username = '';
form.password = '';

View File

@ -2,9 +2,9 @@
<div>
<Submenu activeName="mysql" />
<el-dropdown size="default" split-button style="margin-top: 20px; margin-bottom: 5px">
{{ version }}
{{ mysqlName }}
<template #dropdown>
<el-dropdown-menu v-model="version">
<el-dropdown-menu v-model="mysqlName">
<el-dropdown-item v-for="item in mysqlVersions" :key="item" @click="onChangeVersion(item)">
{{ item }}
</el-dropdown-item>
@ -128,7 +128,7 @@ import { Rules } from '@/global/form-rules';
const selects = ref<any>([]);
const mysqlVersions = ref();
const version = ref<string>('5.7');
const mysqlName = ref<string>('5.7');
const isOnSetting = ref<boolean>();
const data = ref();
@ -141,7 +141,7 @@ const paginationConfig = reactive({
const dialogRef = ref();
const onOpenDialog = async () => {
let params = {
version: version.value,
mysqlName: mysqlName.value,
};
dialogRef.value!.acceptParams(params);
};
@ -149,7 +149,7 @@ const onOpenDialog = async () => {
const dialogBackupRef = ref();
const onOpenBackupDialog = async (dbName: string) => {
let params = {
version: version.value,
mysqlName: mysqlName.value,
dbName: dbName,
};
dialogBackupRef.value!.acceptParams(params);
@ -159,7 +159,7 @@ const settingRef = ref();
const onSetting = async () => {
isOnSetting.value = true;
let params = {
version: version.value,
mysqlName: mysqlName.value,
};
settingRef.value!.acceptParams(params);
};
@ -174,7 +174,7 @@ type FormInstance = InstanceType<typeof ElForm>;
const changeFormRef = ref<FormInstance>();
const changeForm = reactive({
id: 0,
version: '',
mysqlName: '',
userName: '',
password: '',
operation: '',
@ -187,7 +187,7 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
formEl.validate(async (valid) => {
if (!valid) return;
changeForm.value = changeForm.operation === 'password' ? changeForm.password : changeForm.privilege;
changeForm.version = version.value;
changeForm.mysqlName = mysqlName.value;
await updateMysqlDBInfo(changeForm);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
search();
@ -199,17 +199,17 @@ const loadRunningOptions = async () => {
const res = await loadVersions();
mysqlVersions.value = res.data;
if (mysqlVersions.value.length != 0) {
version.value = mysqlVersions.value[0];
mysqlName.value = mysqlVersions.value[0];
search();
}
};
const onChangeVersion = async (val: string) => {
version.value = val;
mysqlName.value = val;
search();
if (isOnSetting.value) {
let params = {
version: version.value,
mysqlName: mysqlName.value,
};
settingRef.value!.acceptParams(params);
}
@ -219,7 +219,7 @@ const search = async () => {
let params = {
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
version: version.value,
mysqlName: mysqlName.value,
};
const res = await searchMysqlDBs(params);
data.value = res.data.items || [];

View File

@ -339,6 +339,7 @@ const baseInfo = reactive({
port: 3306,
password: '',
remoteConn: false,
mysqlKey: '',
});
const panelFormRef = ref<FormInstance>();
const mysqlConf = ref();
@ -347,7 +348,7 @@ const plan = ref();
const variableFormRef = ref<FormInstance>();
let mysqlVariables = reactive({
version: '',
mysqlName: '',
key_buffer_size: 0,
query_cache_size: 0,
tmp_table_size: 0,
@ -404,14 +405,14 @@ let mysqlStatus = reactive({
});
const onSetting = ref<boolean>(false);
const paramVersion = ref();
const mysqlName = ref();
interface DialogProps {
version: string;
mysqlName: string;
}
const acceptParams = (params: DialogProps): void => {
onSetting.value = true;
paramVersion.value = params.version;
mysqlName.value = params.mysqlName;
loadBaseInfo();
loadStatus();
loadVariables();
@ -428,7 +429,7 @@ const onSave = async (formEl: FormInstance | undefined, key: string, val: any) =
}
let changeForm = {
id: 0,
version: paramVersion.value,
mysqlName: mysqlName.value,
value: val,
operation: key === 'remoteConn' ? 'privilege' : key,
};
@ -447,12 +448,13 @@ function callback(error: any) {
}
const loadBaseInfo = async () => {
const res = await loadMysqlBaseInfo(paramVersion.value);
const res = await loadMysqlBaseInfo(mysqlName.value);
baseInfo.name = res.data?.name;
baseInfo.port = res.data?.port;
baseInfo.password = res.data?.password;
baseInfo.remoteConn = res.data?.remoteConn;
loadMysqlConf(`/opt/1Panel/data/apps/${paramVersion.value}/${baseInfo.name}/conf/my.cnf`);
baseInfo.mysqlKey = res.data?.mysqlKey;
loadMysqlConf(`/opt/1Panel/data/apps/${baseInfo.mysqlKey}/${baseInfo.name}/conf/my.cnf`);
};
const loadMysqlConf = async (path: string) => {
@ -461,7 +463,7 @@ const loadMysqlConf = async (path: string) => {
};
const loadVariables = async () => {
const res = await loadMysqlVariables(paramVersion.value);
const res = await loadMysqlVariables(mysqlName.value);
mysqlVariables.key_buffer_size = Number(res.data.key_buffer_size) / 1024 / 1024;
mysqlVariables.query_cache_size = Number(res.data.query_cache_size) / 1024 / 1024;
mysqlVariables.tmp_table_size = Number(res.data.tmp_table_size) / 1024 / 1024;
@ -506,7 +508,7 @@ const onSaveVariables = async (formEl: FormInstance | undefined) => {
formEl.validate(async (valid) => {
if (!valid) return;
let itemForm = {
version: paramVersion.value,
mysqlName: mysqlName.value,
key_buffer_size: mysqlVariables.key_buffer_size * 1024 * 1024,
query_cache_size: mysqlVariables.query_cache_size * 1024 * 1024,
tmp_table_size: mysqlVariables.tmp_table_size * 1024 * 1024,
@ -529,7 +531,7 @@ const onSaveVariables = async (formEl: FormInstance | undefined) => {
};
const loadStatus = async () => {
const res = await loadMysqlStatus(paramVersion.value);
const res = await loadMysqlStatus(mysqlName.value);
let queryPerSecond = res.data.Questions / res.data.Uptime;
let txPerSecond = (res.data!.Com_commit + res.data.Com_rollback) / res.data.Uptime;

View File

@ -1,7 +1,37 @@
<template>
<div>
<Submenu activeName="redis" />
<el-card style="margin-top: 20px">
<el-dropdown size="default" split-button style="margin-top: 20px; margin-bottom: 5px">
{{ redisName }}
<template #dropdown>
<el-dropdown-menu v-model="redisName">
<el-dropdown-item v-for="item in redisNames" :key="item" @click="onChangeName(item)">
{{ item }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button
v-if="!isOnSetting"
style="margin-top: 20px; margin-left: 10px"
size="default"
icon="Setting"
@click="onSetting"
>
{{ $t('database.setting') }}
</el-button>
<el-button
v-if="isOnSetting"
style="margin-top: 20px; margin-left: 10px"
size="default"
icon="Back"
@click="onBacklist"
>
{{ $t('commons.button.back') }}列表
</el-button>
<Setting ref="settingRef"></Setting>
<el-card v-if="!isOnSetting">
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data">
<template #toolbar>
<el-button type="primary" @click="onOperate">{{ $t('commons.button.create') }}</el-button>
@ -80,8 +110,9 @@
<script lang="ts" setup>
import ComplexTable from '@/components/complex-table/index.vue';
import Submenu from '@/views/database/index.vue';
import Setting from '@/views/database/redis/setting/index.vue';
import { onMounted, reactive, ref } from 'vue';
import { cleanRedisKey, deleteRedisKey, searchRedisDBs, setRedis } from '@/api/modules/database';
import { cleanRedisKey, deleteRedisKey, loadRedisVersions, searchRedisDBs, setRedis } from '@/api/modules/database';
import i18n from '@/lang';
import { useDeleteData } from '@/hooks/use-delete-data';
import { Database } from '@/api/interface/database';
@ -113,6 +144,7 @@ const paginationConfig = reactive({
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const form = reactive({
redisName: '',
key: '',
value: '',
db: 0,
@ -126,10 +158,48 @@ const rules = reactive({
});
const redisVisiable = ref(false);
const redisNames = ref();
const redisName = ref();
const isOnSetting = ref(false);
const settingRef = ref();
const onSetting = async () => {
isOnSetting.value = true;
let params = {
redisName: redisName.value,
db: currentDB.value,
};
settingRef.value!.acceptParams(params);
};
const onBacklist = async () => {
isOnSetting.value = false;
search();
settingRef.value!.onClose();
};
const loadRunningNames = async () => {
const res = await loadRedisVersions();
redisNames.value = res.data;
if (redisNames.value.length != 0) {
redisName.value = redisNames.value[0];
search();
}
};
const onChangeName = async (val: string) => {
redisName.value = val;
search();
if (isOnSetting.value) {
let params = {
redisName: redisName.value,
};
settingRef.value!.acceptParams(params);
}
};
const search = async () => {
let params = {
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
redisName: redisName.value,
db: currentDB.value,
};
const res = await searchRedisDBs(params);
@ -147,6 +217,7 @@ const onBatchDelete = async (row: Database.RedisData | null) => {
});
}
let params = {
redisName: redisName.value,
db: form.db,
names: names,
};
@ -161,7 +232,11 @@ const onCleanAll = async () => {
type: 'warning',
draggable: true,
}).then(async () => {
await cleanRedisKey(currentDB.value);
let params = {
redisName: redisName.value,
db: currentDB.value,
};
await cleanRedisKey(params);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
search();
});
@ -186,6 +261,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
form.redisName = redisName.value;
await setRedis(form);
redisVisiable.value = false;
currentDB.value = form.db;
@ -208,8 +284,7 @@ const buttons = [
},
},
];
onMounted(() => {
search();
loadRunningNames();
});
</script>

View File

@ -0,0 +1,360 @@
<template>
<div class="demo-collapse" v-if="onSetting">
<el-card>
<el-collapse v-model="activeName" accordion>
<el-collapse-item :title="$t('database.baseSetting')" name="1">
<el-form :model="baseInfo" ref="panelFormRef" :rules="rules" label-width="120px">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form-item :label="$t('setting.port')" prop="port">
<el-input clearable type="number" v-model.number="baseInfo.port">
<template #append>
<el-button
@click="onSave(panelFormRef, 'port', baseInfo.port)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="requirepass">
<el-input type="password" show-password clearable v-model="baseInfo.requirepass">
<template #append>
<el-button
@click="onSave(panelFormRef, 'password', baseInfo.requirepass)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('database.requirepassHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.timeout')" prop="timeout">
<el-input clearable type="number" v-model.number="baseInfo.timeout">
<template #append>
<el-button
@click="onSave(panelFormRef, 'timeout', baseInfo.timeout)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('database.timeoutHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.maxclients')" prop="maxclients">
<el-input clearable type="number" v-model.number="baseInfo.maxclients">
<template #append>
<el-button
@click="onSave(panelFormRef, 'maxclients', baseInfo.maxclients)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('database.databases')" prop="databases">
<el-input clearable type="number" v-model.number="baseInfo.databases">
<template #append>
<el-button
@click="onSave(panelFormRef, 'databases', baseInfo.databases)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('database.maxmemory')" prop="maxmemory">
<el-input clearable type="number" v-model.number="baseInfo.maxmemory">
<template #append>
<el-button
@click="onSave(panelFormRef, 'maxmemory', baseInfo.maxmemory)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('database.maxmemoryHelper') }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-collapse-item>
<el-collapse-item :title="$t('database.confChange')" name="2">
<codemirror
:autofocus="true"
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; max-height: 500px"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="mysqlConf"
:readOnly="true"
/>
<el-button
type="primary"
style="width: 120px; margin-top: 10px"
@click="onSave(panelFormRef, 'remoteAccess', baseInfo.port)"
>
{{ $t('commons.button.save') }}
</el-button>
</el-collapse-item>
<el-collapse-item :title="$t('database.currentStatus')" name="3">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="12">
<table style="margin-top: 20px; width: 100%" class="myTable">
<tr>
<td>uptime_in_days</td>
<td>{{ redisStatus!.uptime_in_days }}</td>
<td>{{ $t('database.uptimeInDays') }}</td>
</tr>
<tr>
<td>tcp_port</td>
<td>{{ redisStatus!.tcp_port }}</td>
<td>{{ $t('database.tcpPort') }}</td>
</tr>
<tr>
<td>connected_clients</td>
<td>{{ redisStatus!.connected_clients }}</td>
<td>{{ $t('database.connectedClients') }}</td>
</tr>
<tr>
<td>used_memory_rss</td>
<td>{{ redisStatus!.used_memory_rss }}</td>
<td>{{ $t('database.usedMemoryRss') }}</td>
</tr>
<tr>
<td>used_memory</td>
<td>{{ redisStatus!.used_memory }}</td>
<td>{{ $t('database.usedMemory') }}</td>
</tr>
<tr>
<td>mem_fragmentation_ratio</td>
<td>{{ redisStatus!.mem_fragmentation_ratio }}</td>
<td>{{ $t('database.tmpTableToDBHelper') }}</td>
</tr>
<tr>
<td>total_connections_received</td>
<td>{{ redisStatus!.total_connections_received }}</td>
<td>{{ $t('database.totalConnectionsReceived') }}</td>
</tr>
<tr>
<td>total_commands_processed</td>
<td>{{ redisStatus!.total_commands_processed }}</td>
<td>{{ $t('database.totalCommandsProcessed') }}</td>
</tr>
<tr>
<td>instantaneous_ops_per_sec</td>
<td>{{ redisStatus!.instantaneous_ops_per_sec }}</td>
<td>{{ $t('database.instantaneousOpsPerSec') }}</td>
</tr>
<tr>
<td>keyspace_hits</td>
<td>{{ redisStatus!.keyspace_hits }}</td>
<td>{{ $t('database.keyspaceHits') }}</td>
</tr>
<tr>
<td>keyspace_misses</td>
<td>{{ redisStatus!.keyspace_misses }}</td>
<td>{{ $t('database.keyspaceMisses') }}</td>
</tr>
<tr>
<td>hit</td>
<td>{{ redisStatus!.hit }}</td>
<td>{{ $t('database.hit') }}</td>
</tr>
<tr>
<td>latest_fork_usec</td>
<td>{{ redisStatus!.latest_fork_usec }}</td>
<td>{{ $t('database.latestForkUsec') }}</td>
</tr>
</table>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item :title="$t('database.persistence')" name="4">
<el-form :model="baseInfo" ref="panelFormRef" label-width="120px">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form-item label="appendonly" prop="appendonly">
<el-switch v-model="baseInfo.appendonly"></el-switch>
</el-form-item>
<el-form-item label="appendfsync" prop="appendfsync">
<el-radio-group v-model="baseInfo.appendfsync">
<el-radio label="always">always</el-radio>
<el-radio label="everysec">everysec</el-radio>
<el-radio label="no">no</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-collapse-item>
</el-collapse>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { ElMessage, FormInstance } from 'element-plus';
import { reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import { loadRedisConf, loadRedisStatus, updateRedisConf } from '@/api/modules/database';
import i18n from '@/lang';
import { Rules } from '@/global/form-rules';
const extensions = [javascript(), oneDark];
const activeName = ref('1');
const baseInfo = reactive({
port: 3306,
requirepass: '',
timeout: 0,
maxclients: 0,
databases: 0,
maxmemory: 0,
dir: '',
appendonly: '',
appendfsync: '',
save: '',
});
const rules = reactive({
port: [Rules.port],
timeout: [Rules.number],
maxclients: [Rules.number],
databases: [Rules.number],
maxmemory: [Rules.number],
appendonly: [Rules.requiredSelect],
appendfsync: [Rules.requiredSelect],
});
const panelFormRef = ref<FormInstance>();
const mysqlConf = ref();
let redisStatus = reactive({
tcp_port: '',
uptime_in_days: '',
connected_clients: '',
used_memory: '',
used_memory_rss: '',
used_memory_peak: '',
mem_fragmentation_ratio: '',
total_connections_received: '',
total_commands_processed: '',
instantaneous_ops_per_sec: '',
keyspace_hits: '',
keyspace_misses: '',
hit: '',
latest_fork_usec: '',
});
const onSetting = ref<boolean>(false);
const redisName = ref();
const db = ref();
interface DialogProps {
redisName: string;
db: number;
}
const acceptParams = (params: DialogProps): void => {
onSetting.value = true;
redisName.value = params.redisName;
db.value = params.db;
loadBaseInfo();
loadStatus();
};
const onClose = (): void => {
onSetting.value = false;
};
const onSave = async (formEl: FormInstance | undefined, key: string, val: any) => {
if (!formEl) return;
const result = await formEl.validateField(key, callback);
if (!result) {
return;
}
let changeForm = {
redisName: redisName.value,
db: 0,
paramName: key,
value: val + '',
};
await updateRedisConf(changeForm);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
};
function callback(error: any) {
if (error) {
return error.message;
} else {
return;
}
}
const loadBaseInfo = async () => {
let params = {
redisName: redisName.value,
db: db.value,
};
const res = await loadRedisConf(params);
baseInfo.timeout = Number(res.data?.timeout);
baseInfo.maxclients = Number(res.data?.maxclients);
baseInfo.databases = Number(res.data?.databases);
baseInfo.requirepass = res.data?.requirepass;
baseInfo.maxmemory = Number(res.data?.maxmemory);
baseInfo.appendonly = res.data?.appendonly;
baseInfo.appendfsync = res.data?.appendfsync;
loadMysqlConf(`/opt/1Panel/data/apps/redis/${redisName.value}/conf/redis.conf`);
};
const loadMysqlConf = async (path: string) => {
const res = await LoadFile({ path: path });
mysqlConf.value = res.data;
};
const loadStatus = async () => {
let params = {
redisName: redisName.value,
db: db.value,
};
const res = await loadRedisStatus(params);
let hit = (
(Number(res.data.keyspace_hits) / (Number(res.data.keyspace_hits) + Number(res.data.keyspace_misses))) *
100
).toFixed(2);
redisStatus.uptime_in_days = res.data.uptime_in_days;
redisStatus.tcp_port = res.data.tcp_port;
redisStatus.connected_clients = res.data.connected_clients;
redisStatus.used_memory_rss = (Number(res.data.used_memory_rss) / 1024 / 1024).toFixed(2) + ' MB';
redisStatus.used_memory = (Number(res.data.used_memory) / 1024 / 1024).toFixed(2) + ' MB';
redisStatus.mem_fragmentation_ratio = res.data.mem_fragmentation_ratio;
redisStatus.total_connections_received = res.data.total_connections_received;
redisStatus.total_commands_processed = res.data.total_commands_processed;
redisStatus.instantaneous_ops_per_sec = res.data.instantaneous_ops_per_sec;
redisStatus.keyspace_hits = res.data.keyspace_hits;
redisStatus.keyspace_misses = res.data.keyspace_misses;
redisStatus.hit = hit;
redisStatus.latest_fork_usec = res.data.latest_fork_usec;
};
defineExpose({
acceptParams,
onClose,
});
</script>