From ab2cf0d0c3b928338f33ef1eff974b7e03d8eaf4 Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Mon, 14 Jul 2025 19:08:57 +0800 Subject: [PATCH] feat: add cluster status page (#9514) --- agent/app/api/v2/backup.go | 6 +-- agent/app/dto/backup.go | 4 +- agent/app/dto/database.go | 12 +++--- agent/app/service/app_install.go | 8 +++- agent/app/service/app_utils.go | 10 ++--- agent/app/service/database_common.go | 4 +- agent/app/service/database_mysql.go | 12 ++++-- agent/utils/mysql/client.go | 6 ++- core/app/api/v2/helper/helper.go | 16 +++++--- .../src/components/log/container/index.vue | 1 - frontend/src/lang/modules/en.ts | 1 + frontend/src/lang/modules/ja.ts | 1 + frontend/src/lang/modules/ko.ts | 1 + frontend/src/lang/modules/ms.ts | 1 + frontend/src/lang/modules/pt-br.ts | 1 + frontend/src/lang/modules/ru.ts | 1 + frontend/src/lang/modules/tr.ts | 1 + frontend/src/lang/modules/zh-Hant.ts | 1 + frontend/src/lang/modules/zh.ts | 1 + frontend/src/utils/app.ts | 1 - .../views/app-store/detail/params/index.vue | 38 +++++++++---------- .../app-store/installed/detail/index.vue | 1 - frontend/src/views/database/mysql/index.vue | 16 ++++++-- .../views/database/mysql/setting/index.vue | 3 +- 24 files changed, 92 insertions(+), 55 deletions(-) diff --git a/agent/app/api/v2/backup.go b/agent/app/api/v2/backup.go index 83dea48e2..7f003923e 100644 --- a/agent/app/api/v2/backup.go +++ b/agent/app/api/v2/backup.go @@ -371,12 +371,12 @@ func (b *BaseApi) Backup(c *gin.Context) { helper.InternalServer(c, err) return } - case "mysql", "mariadb": + case "mysql", "mariadb", constant.AppMysqlCluster: if err := backupService.MysqlBackup(req); err != nil { helper.InternalServer(c, err) return } - case constant.AppPostgresql: + case constant.AppPostgresql, constant.AppPostgresqlCluster: if err := backupService.PostgresqlBackup(req); err != nil { helper.InternalServer(c, err) return @@ -386,7 +386,7 @@ func (b *BaseApi) Backup(c *gin.Context) { helper.InternalServer(c, err) return } - case "redis": + case "redis", constant.AppRedisCluster: if err := backupService.RedisBackup(req); err != nil { helper.InternalServer(c, err) return diff --git a/agent/app/dto/backup.go b/agent/app/dto/backup.go index e8405188b..30b58d289 100644 --- a/agent/app/dto/backup.go +++ b/agent/app/dto/backup.go @@ -54,7 +54,7 @@ type BackupOption struct { } type CommonBackup struct { - Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"` + Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"` Name string `json:"name"` DetailName string `json:"detailName"` Secret string `json:"secret"` @@ -65,7 +65,7 @@ type CommonBackup struct { } type CommonRecover struct { DownloadAccountID uint `json:"downloadAccountID" validate:"required"` - Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"` + Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"` Name string `json:"name"` DetailName string `json:"detailName"` File string `json:"file"` diff --git a/agent/app/dto/database.go b/agent/app/dto/database.go index e24b421c9..e2fc96c21 100644 --- a/agent/app/dto/database.go +++ b/agent/app/dto/database.go @@ -4,14 +4,14 @@ import "time" // common type DBConfUpdateByFile struct { - Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql redis"` + Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql redis mysql-cluster postgresql-cluster"` Database string `json:"database" validate:"required"` File string `json:"file"` } type ChangeDBInfo struct { ID uint `json:"id"` From string `json:"from" validate:"required,oneof=local remote"` - Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql"` + Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql mysql-cluster postgresql-cluster"` Database string `json:"database" validate:"required"` Value string `json:"value" validate:"required"` } @@ -74,19 +74,19 @@ type BindUser struct { type MysqlLoadDB struct { From string `json:"from" validate:"required,oneof=local remote"` - Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"` Database string `json:"database" validate:"required"` } type MysqlDBDeleteCheck struct { ID uint `json:"id" validate:"required"` - Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"` Database string `json:"database" validate:"required"` } type MysqlDBDelete struct { ID uint `json:"id" validate:"required"` - Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"` Database string `json:"database" validate:"required"` ForceDelete bool `json:"forceDelete"` DeleteBackup bool `json:"deleteBackup"` @@ -153,7 +153,7 @@ type MysqlVariables struct { } type MysqlVariablesUpdate struct { - Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"` Database string `json:"database" validate:"required"` Variables []MysqlVariablesUpdateHelper `json:"variables"` } diff --git a/agent/app/service/app_install.go b/agent/app/service/app_install.go index 942a5496d..e73de2b47 100644 --- a/agent/app/service/app_install.go +++ b/agent/app/service/app_install.go @@ -476,7 +476,11 @@ func (a *AppInstallService) GetServices(key string) ([]response.AppService, erro if key == constant.AppPostgres { key = constant.AppPostgresql } - dbs, _ := databaseRepo.GetList(repo.WithByType(key)) + types := []string{key} + if key == constant.AppMysql { + types = []string{constant.AppMysql, constant.AppMysqlCluster} + } + dbs, _ := databaseRepo.GetList(repo.WithTypes(types)) if len(dbs) == 0 { return res, nil } @@ -659,7 +663,7 @@ func (a *AppInstallService) GetDefaultConfigByKey(key, name string) (string, err return "", buserr.New("ErrPathNotFound") } - if key == constant.AppMysql || key == constant.AppMariaDB { + if key == constant.AppMysql || key == constant.AppMariaDB || key == constant.AppMysqlCluster { filePath = path.Join(filePath, "my.cnf") } if key == constant.AppRedis { diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go index 2119e115b..1142141e6 100644 --- a/agent/app/service/app_utils.go +++ b/agent/app/service/app_utils.go @@ -254,7 +254,7 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI var resourceId uint if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" { switch database.Type { - case constant.AppPostgresql, constant.AppPostgres: + case constant.AppPostgresql, constant.AppPostgres, constant.AppPostgresqlCluster: oldPostgresqlDb, _ := postgresqlRepo.Get(repo.WithByName(dbConfig.DbName), repo.WithByFrom(constant.ResourceLocal)) resourceId = oldPostgresqlDb.ID if oldPostgresqlDb.ID > 0 { @@ -276,7 +276,7 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI } resourceId = pgdb.ID } - case constant.AppMysql, constant.AppMariaDB: + case constant.AppMysql, constant.AppMariaDB, constant.AppMysqlCluster: oldMysqlDb, _ := mysqlRepo.Get(repo.WithByName(dbConfig.DbName), repo.WithByFrom(constant.ResourceLocal)) resourceId = oldMysqlDb.ID if oldMysqlDb.ID > 0 { @@ -407,9 +407,9 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error { } switch install.App.Key { - case constant.AppMysql, constant.AppMariaDB: + case constant.AppMysql, constant.AppMariaDB, constant.AppMysqlCluster: _ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name)) - case constant.AppPostgresql: + case constant.AppPostgresql, constant.AppPostgresqlCluster: _ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(install.Name)) } @@ -1494,7 +1494,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) continue } lastVersion := versions[0] - if app.Key == constant.AppMysql { + if app.Key == constant.AppMysql || app.Key == constant.AppMysqlCluster { for _, version := range versions { majorVersion := getMajorVersion(installed.Version) if !strings.HasPrefix(version, majorVersion) { diff --git a/agent/app/service/database_common.go b/agent/app/service/database_common.go index f16340fff..1b23c1c77 100644 --- a/agent/app/service/database_common.go +++ b/agent/app/service/database_common.go @@ -34,7 +34,7 @@ func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.D } data.ContainerName = app.ContainerName data.Name = app.Name - data.Port = int64(app.Port) + data.Port = app.Port return &data, nil } @@ -42,6 +42,8 @@ func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.D func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) { filePath := "" switch req.Type { + case "mysql-cluster-conf": + filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql-cluster/%s/conf/my.cnf", req.Name)) case "mysql-conf": filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name)) case "mariadb-conf": diff --git a/agent/app/service/database_mysql.go b/agent/app/service/database_mysql.go index 5766a5ba0..01b3743ac 100644 --- a/agent/app/service/database_mysql.go +++ b/agent/app/service/database_mysql.go @@ -534,7 +534,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS info.File = "OFF" info.Position = "OFF" masterStatus := "show master status;" - if common.CompareAppVersion(app.Version, "8.4.0") && req.Type == constant.AppMysql { + if common.CompareAppVersion(app.Version, "8.4.0") && (req.Type == constant.AppMysql || req.Type == constant.AppMysqlCluster) { masterStatus = "show binary log status;" } rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, masterStatus) @@ -553,10 +553,13 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS } func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) { + if dbType == "mysql-cluster" { + dbType = "mysql" + } cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command) stdout, err := cmd.CombinedOutput() stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "") - if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") { + if err != nil || strings.HasPrefix(stdStr, "ERROR ") { return nil, errors.New(stdStr) } @@ -572,10 +575,13 @@ func executeSqlForMaps(containerName, dbType, password, command string) (map[str } func executeSqlForRows(containerName, dbType, password, command string) ([]string, error) { + if dbType == "mysql-cluster" { + dbType = "mysql" + } cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command) stdout, err := cmd.CombinedOutput() stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "") - if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") { + if err != nil || strings.HasPrefix(stdStr, "ERROR ") { return nil, errors.New(stdStr) } return strings.Split(stdStr, "\n"), nil diff --git a/agent/utils/mysql/client.go b/agent/utils/mysql/client.go index 17a413d67..d4d189de0 100644 --- a/agent/utils/mysql/client.go +++ b/agent/utils/mysql/client.go @@ -30,7 +30,11 @@ type MysqlClient interface { func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) { if conn.From == "local" { - connArgs := []string{"exec", conn.Address, conn.Type, "-u" + conn.Username, "-p" + conn.Password, "-e"} + mysqlCli := conn.Type + if mysqlCli == "mysql-cluster" { + mysqlCli = "mysql" + } + connArgs := []string{"exec", conn.Address, mysqlCli, "-u" + conn.Username, "-p" + conn.Password, "-e"} return client.NewLocal(connArgs, conn.Type, conn.Address, conn.Password, conn.Database), nil } diff --git a/core/app/api/v2/helper/helper.go b/core/app/api/v2/helper/helper.go index 4d374f0ac..dd97c372f 100644 --- a/core/app/api/v2/helper/helper.go +++ b/core/app/api/v2/helper/helper.go @@ -1,9 +1,11 @@ package helper import ( + "errors" "fmt" "github.com/1Panel-dev/1Panel/core/cmd/server/res" "net/http" + "strconv" "github.com/1Panel-dev/1Panel/core/app/dto" "github.com/1Panel-dev/1Panel/core/global" @@ -70,11 +72,6 @@ func CheckBindAndValidate(req interface{}, c *gin.Context) error { return nil } -func ErrResponse(ctx *gin.Context, code int) { - ctx.JSON(code, nil) - ctx.Abort() -} - func ErrWithHtml(ctx *gin.Context, code int, scope string) { if code == 444 { ctx.String(444, "") @@ -94,3 +91,12 @@ func ErrWithHtml(ctx *gin.Context, code int, scope string) { ctx.Data(code, "text/html; charset=utf-8", data) ctx.Abort() } + +func GetParamID(c *gin.Context) (uint, error) { + idParam, ok := c.Params.Get("id") + if !ok { + return 0, errors.New("error id in path") + } + intNum, _ := strconv.Atoi(idParam) + return uint(intNum), nil +} diff --git a/frontend/src/components/log/container/index.vue b/frontend/src/components/log/container/index.vue index e1d3c9c6c..d70649f83 100644 --- a/frontend/src/components/log/container/index.vue +++ b/frontend/src/components/log/container/index.vue @@ -206,7 +206,6 @@ const onClean = async () => { cancelButtonText: i18n.global.t('commons.button.cancel'), type: 'info', }).then(async () => { - console.log(logSearch); await cleanContainerLog(logSearch.container); searchLogs(); MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index cecb149b4..122d83993 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -3647,6 +3647,7 @@ const message = { installNode: 'Install Node', master: 'Master Node', slave: 'Slave Node', + replicaStatus: 'Master-Slave Status', }, }, }; diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 31f2f2143..7d1a4e949 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -3510,6 +3510,7 @@ const message = { installNode: 'ノードをインストール', master: 'マスターノード', slave: 'スレーブノード', + replicaStatus: 'マスタースレーブステータス', }, }, }; diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 23249a2cc..e0a3e1ceb 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -3448,6 +3448,7 @@ const message = { installNode: '노드 설치', master: '마스터 노드', slave: '슬레이브 노드', + replicaStatus: '마스터-슬레이브 상태', }, }, }; diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 8de091344..31ad35a1a 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -3591,6 +3591,7 @@ const message = { installNode: 'Pasang Node', master: 'Node Utama', slave: 'Node Hamba', + replicaStatus: 'Utama-Hamba Status', }, }, }; diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 044d24664..dc3d6d6c5 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -3598,6 +3598,7 @@ const message = { installNode: 'Instalar Nó', master: 'Nó Mestre', slave: 'Nó Escravo', + replicaStatus: 'Status Mestre-Escravo', }, }, }; diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 71a4469b0..689033ae6 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -3589,6 +3589,7 @@ const message = { installNode: 'Установить узел', master: 'Главный узел', slave: 'Подчиненный узел', + replicaStatus: 'Состояние мастер-слейв', }, }, }; diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index e8320e2df..6138c1215 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -3687,6 +3687,7 @@ const message = { installNode: 'Установить узел', master: 'Главный узел', slave: 'Подчиненный узел', + replicaStatus: 'Ana-Çalışan Durumu', }, }, }; diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 5a1542dd0..869715423 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -3392,6 +3392,7 @@ const message = { installNode: '安裝節點', master: '主節點', slave: '從節點', + replicaStatus: '主從狀態', }, }, }; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 7c6814f86..9ca580075 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -3372,6 +3372,7 @@ const message = { installNode: '安装节点', master: '主节点', slave: '从节点', + replicaStatus: '主从状态', }, }, }; diff --git a/frontend/src/utils/app.ts b/frontend/src/utils/app.ts index 8928ee6b4..2799846bf 100644 --- a/frontend/src/utils/app.ts +++ b/frontend/src/utils/app.ts @@ -14,7 +14,6 @@ export const jumpToInstall = (type: string, key: string) => { } switch (key) { case 'mysql-cluster': - console.log('jumpToInstall mysql-cluster'); jumpToPath(router, '/xpack/cluster/mysql'); return true; case 'redis-cluster': diff --git a/frontend/src/views/app-store/detail/params/index.vue b/frontend/src/views/app-store/detail/params/index.vue index 4dd2244db..3975ce9e4 100644 --- a/frontend/src/views/app-store/detail/params/index.vue +++ b/frontend/src/views/app-store/detail/params/index.vue @@ -56,8 +56,8 @@ :label="service.label" > - - +
+
- - +
+
- + {{ service.label }} - + {{ $t('commons.table.local') }} {{ $t('database.remote') }} + - - - - - - - - {{ $t('app.toInstall') }} - - - - +
+ + + {{ $t('app.toInstall') }} + + +
{{ getDescription(p) }} diff --git a/frontend/src/views/app-store/installed/detail/index.vue b/frontend/src/views/app-store/installed/detail/index.vue index 1fbdebd9a..a61644c4d 100644 --- a/frontend/src/views/app-store/installed/detail/index.vue +++ b/frontend/src/views/app-store/installed/detail/index.vue @@ -234,7 +234,6 @@ const get = async () => { if (d.type === 'number') { value = Number(value); } - console.log('d', d); params.value.push({ default: value, labelEn: d.labelEn, diff --git a/frontend/src/views/database/mysql/index.vue b/frontend/src/views/database/mysql/index.vue index 9eb1aef6c..572060b75 100644 --- a/frontend/src/views/database/mysql/index.vue +++ b/frontend/src/views/database/mysql/index.vue @@ -12,7 +12,7 @@ - +