diff --git a/agent/app/api/v2/database_redis.go b/agent/app/api/v2/database_redis.go index 415a11844..2a0657089 100644 --- a/agent/app/api/v2/database_redis.go +++ b/agent/app/api/v2/database_redis.go @@ -11,13 +11,13 @@ import ( // @Tags Database Redis // @Summary Load redis status info // @Accept json -// @Param request body dto.OperationWithName true "request" +// @Param request body dto.LoadRedisStatus true "request" // @Success 200 {object} dto.RedisStatus // @Security ApiKeyAuth // @Security Timestamp // @Router /databases/redis/status [post] func (b *BaseApi) LoadRedisStatus(c *gin.Context) { - var req dto.OperationWithName + var req dto.LoadRedisStatus if err := helper.CheckBind(&req, c); err != nil { return } diff --git a/agent/app/api/v2/terminal.go b/agent/app/api/v2/terminal.go index bef0739b7..6ff5b5e6d 100644 --- a/agent/app/api/v2/terminal.go +++ b/agent/app/api/v2/terminal.go @@ -89,8 +89,8 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) { var containerID string var initCmd []string switch source { - case "redis": - containerID, initCmd, err = loadRedisInitCmd(c) + case "redis", "redis-cluster": + containerID, initCmd, err = loadRedisInitCmd(c, source) case "ollama": containerID, initCmd, err = loadOllamaInitCmd(c) case "container": @@ -127,7 +127,7 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) { _ = wsConn.WriteControl(websocket.CloseMessage, nil, dt) } -func loadRedisInitCmd(c *gin.Context) (string, []string, error) { +func loadRedisInitCmd(c *gin.Context, redisType string) (string, []string, error) { name := c.Query("name") from := c.Query("from") commands := []string{"exec", "-it"} @@ -136,7 +136,7 @@ func loadRedisInitCmd(c *gin.Context) (string, []string, error) { return "", nil, fmt.Errorf("no such database in db, err: %v", err) } if from == "local" { - redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: "redis"}) + redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: redisType}) if err != nil { return "", nil, fmt.Errorf("no such app in db, err: %v", err) } diff --git a/agent/app/dto/database.go b/agent/app/dto/database.go index e2fc96c21..79bfb85d5 100644 --- a/agent/app/dto/database.go +++ b/agent/app/dto/database.go @@ -319,3 +319,8 @@ type DatabaseDelete struct { ForceDelete bool `json:"forceDelete"` DeleteBackup bool `json:"deleteBackup"` } + +type LoadRedisStatus struct { + Name string `json:"name" validate:"required"` + Type string `json:"type" validate:"required"` +} diff --git a/agent/app/service/app_install.go b/agent/app/service/app_install.go index 098572566..8dd37f062 100644 --- a/agent/app/service/app_install.go +++ b/agent/app/service/app_install.go @@ -482,6 +482,8 @@ func (a *AppInstallService) GetServices(key string) ([]response.AppService, erro types = []string{constant.AppMysql, constant.AppMysqlCluster} case constant.AppPostgresql: types = []string{constant.AppPostgresql, constant.AppPostgresqlCluster} + case constant.AppRedis: + types = []string{constant.AppRedis, constant.AppRedisCluster} } dbs, _ := databaseRepo.GetList(repo.WithTypes(types)) diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go index e94fece87..276311a73 100644 --- a/agent/app/service/app_utils.go +++ b/agent/app/service/app_utils.go @@ -125,6 +125,7 @@ var DatabaseKeys = map[string]uint{ constant.AppMemcached: 11211, constant.AppMysqlCluster: 3306, constant.AppPostgresqlCluster: 5432, + constant.AppRedisCluster: 6379, } var ToolKeys = map[string]uint{ diff --git a/agent/app/service/database_common.go b/agent/app/service/database_common.go index be794d620..34d54d485 100644 --- a/agent/app/service/database_common.go +++ b/agent/app/service/database_common.go @@ -54,6 +54,8 @@ func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (st filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name)) case "redis-conf": filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name)) + case "redis-cluster-conf": + filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/redis-cluster/%s/conf/redis.conf", req.Name)) } if _, err := os.Stat(filePath); err != nil { return "", buserr.New("ErrHttpReqNotFound") diff --git a/agent/app/service/database_redis.go b/agent/app/service/database_redis.go index af0b15b92..57ef7a96c 100644 --- a/agent/app/service/database_redis.go +++ b/agent/app/service/database_redis.go @@ -28,7 +28,7 @@ type IRedisService interface { UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error ChangePassword(info dto.ChangeRedisPass) error - LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error) + LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error) LoadConf(req dto.OperationWithName) (*dto.RedisConf, error) LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error) @@ -129,8 +129,8 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) return nil } -func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error) { - redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name) +func (u *RedisService) LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error) { + redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name) if err != nil { return nil, err } diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index c1d345653..7fafde8f6 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -108,8 +108,8 @@ export const loadRemoteAccess = (type: string, database: string) => { }; // redis -export const loadRedisStatus = (database: string) => { - return http.post(`/databases/redis/status`, { name: database }); +export const loadRedisStatus = (type: string, database: string) => { + return http.post(`/databases/redis/status`, { type: type, name: database }); }; export const loadRedisConf = (database: string) => { return http.post(`/databases/redis/conf`, { name: database }); diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 8b4d97c7d..f331cc9ba 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -3657,6 +3657,8 @@ const message = { master: 'Master Node', slave: 'Slave Node', replicaStatus: 'Master-Slave Status', + unhealthyDeleteError: 'The installation node status is abnormal, please check the node list and try again!', + replicaStatusError: 'Status acquisition is abnormal, please check the master node.', }, }, }; diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index c2c69cae7..d660f0664 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -3520,6 +3520,9 @@ const message = { master: 'マスターノード', slave: 'スレーブノード', replicaStatus: 'マスタースレーブステータス', + unhealthyDeleteError: + 'インストールノードのステータスが異常です。ノードリストを確認してから再試行してください!', + replicaStatusError: 'ステータスの取得が異常です。マスターノードを確認してください。', }, }, }; diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 743a9305a..960d86bf9 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -3458,6 +3458,8 @@ const message = { master: '마스터 노드', slave: '슬레이브 노드', replicaStatus: '마스터-슬레이브 상태', + unhealthyDeleteError: '설치 노드 상태가 비정상입니다. 노드 목록을 확인한 후 다시 시도하세요!', + replicaStatusError: '상태 획득이 비정상입니다. 마스터 노드를 확인하세요.', }, }, }; diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 76ad9802f..585dbce82 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -3601,6 +3601,8 @@ const message = { master: 'Node Utama', slave: 'Node Hamba', replicaStatus: 'Utama-Hamba Status', + unhealthyDeleteError: 'Status nod pemasangan tidak normal, sila periksa senarai nod dan cuba lagi!', + replicaStatusError: 'Pengambilan status tidak normal, sila periksa nod utama.', }, }, }; diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 6dd94dba5..a627b9a64 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -3608,6 +3608,9 @@ const message = { master: 'Nó Mestre', slave: 'Nó Escravo', replicaStatus: 'Status Mestre-Escravo', + unhealthyDeleteError: + 'O status do nó de instalação está anormal, verifique a lista de nós e tente novamente!', + replicaStatusError: 'A aquisição do status está anormal, verifique o nó mestre.', }, }, }; diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 476a41873..a3a45c036 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -3599,6 +3599,9 @@ const message = { master: 'Главный узел', slave: 'Подчиненный узел', replicaStatus: 'Состояние мастер-слейв', + unhealthyDeleteError: + 'Состояние узла установки аномально, пожалуйста, проверьте список узлов и повторите попытку!', + replicaStatusError: 'Получение статуса аномально, пожалуйста, проверьте главный узел.', }, }, }; diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 4c4dfb10b..5429533a5 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -3697,6 +3697,9 @@ const message = { master: 'Главный узел', slave: 'Подчиненный узел', replicaStatus: 'Ana-Çalışan Durumu', + unhealthyDeleteError: + 'Yükleme düğümü durumu anormal, lütfen düğüm listesini kontrol edin ve tekrar deneyin!', + replicaStatusError: 'Durum alımı anormal, lütfen ana düğümü kontrol edin.', }, }, }; diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index c2d5c9270..6a848bd81 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -3402,6 +3402,8 @@ const message = { master: '主節點', slave: '從節點', replicaStatus: '主從狀態', + unhealthyDeleteError: '安裝節點狀態異常,請在節點列表檢查後重試!', + replicaStatusError: '狀態獲取異常,請檢查主節點。', }, }, }; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 718726977..5501f1400 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -3382,6 +3382,8 @@ const message = { master: '主节点', slave: '从节点', replicaStatus: '主从状态', + unhealthyDeleteError: '安装节点状态异常,请在节点列表检查后重试!', + replicaStatusError: '状态获取异常 请检查主节点', }, }, }; diff --git a/frontend/src/views/database/redis/index.vue b/frontend/src/views/database/redis/index.vue index f366b12b0..55e94699a 100644 --- a/frontend/src/views/database/redis/index.vue +++ b/frontend/src/views/database/redis/index.vue @@ -188,7 +188,7 @@ const onSetting = async () => { isOnSetting.value = true; terminalRef.value?.onClose(false); terminalShow.value = false; - settingRef.value!.acceptParams({ status: redisStatus.value, database: currentDBName.value }); + settingRef.value!.acceptParams({ status: redisStatus.value, database: currentDBName.value, type: appKey.value }); }; const loadHeight = () => { @@ -244,7 +244,7 @@ const changeDatabase = async () => { const loadDBOptions = async () => { try { - const res = await listDatabases('redis'); + const res = await listDatabases('redis,redis-cluster'); let datas = res.data || []; dbOptionsLocal.value = []; dbOptionsRemote.value = []; @@ -318,8 +318,10 @@ const initTerminal = async () => { isRefresh.value = !isRefresh.value; return; } - await checkAppInstalled('redis', currentDBName.value) + console.log(currentDBName.value); + await checkAppInstalled(currentDB.value.type, currentDBName.value) .then((res) => { + console.log(res.data); redisIsExist.value = res.data.isExist; redisStatus.value = res.data.status; loading.value = false; @@ -328,7 +330,7 @@ const initTerminal = async () => { terminalShow.value = true; terminalRef.value.acceptParams({ endpoint: '/api/v2/containers/exec', - args: `source=redis&name=${currentDBName.value}&from=${currentDB.value.from}`, + args: `source=${currentDB.value.type}&name=${currentDBName.value}&from=${currentDB.value.from}`, error: '', initCmd: '', }); diff --git a/frontend/src/views/database/redis/setting/index.vue b/frontend/src/views/database/redis/setting/index.vue index faeed4f60..ef65ad1e3 100644 --- a/frontend/src/views/database/redis/setting/index.vue +++ b/frontend/src/views/database/redis/setting/index.vue @@ -153,6 +153,7 @@ const useOld = ref(false); const redisStatus = ref(); const database = ref(); +const dbType = ref('redis'); const formRef = ref(); const redisConf = ref(); @@ -163,6 +164,7 @@ const settingShow = ref(false); interface DialogProps { database: string; status: string; + type: string; } const changeTab = (val: string) => { @@ -179,7 +181,7 @@ const changeTab = (val: string) => { loadForm(); break; case 'status': - statusRef.value!.acceptParams({ status: redisStatus.value, database: database.value }); + statusRef.value!.acceptParams({ status: redisStatus.value, database: database.value, type: dbType.value }); break; } }; @@ -191,6 +193,7 @@ const changeLoading = (status: boolean) => { const acceptParams = (prop: DialogProps): void => { redisStatus.value = prop.status; database.value = prop.database; + dbType.value = prop.type; settingShow.value = true; changeTab('status'); }; @@ -274,7 +277,7 @@ const submitForm = async () => { const getDefaultConfig = async () => { loading.value = true; - await getAppDefaultConfig('redis', '') + await getAppDefaultConfig(dbType.value, '') .then((res) => { redisConf.value = res.data; useOld.value = true; @@ -323,7 +326,7 @@ const loadForm = async () => { const loadConfFile = async () => { useOld.value = false; loading.value = true; - await loadDBFile('redis-conf', database.value) + await loadDBFile(dbType.value + '-conf', database.value) .then((res) => { loading.value = false; redisConf.value = res.data; diff --git a/frontend/src/views/database/redis/setting/status/index.vue b/frontend/src/views/database/redis/setting/status/index.vue index e5115b239..15e9eecf9 100644 --- a/frontend/src/views/database/redis/setting/status/index.vue +++ b/frontend/src/views/database/redis/setting/status/index.vue @@ -163,21 +163,25 @@ const redisStatus = reactive({ const database = ref(); const statusShow = ref(false); +const dbType = ref('redis'); interface DialogProps { database: string; status: string; + type: string; } const acceptParams = (prop: DialogProps): void => { statusShow.value = true; database.value = prop.database; + dbType.value = prop.type; if (prop.status === 'Running') { loadStatus(); } }; const loadStatus = async () => { - const res = await loadRedisStatus(database.value); + console.log('loadStatus', database.value); + const res = await loadRedisStatus(dbType.value, database.value); let hit = ( (Number(res.data.keyspace_hits) / (Number(res.data.keyspace_hits) + Number(res.data.keyspace_misses))) * 100