mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-31 03:07:34 +08:00
feat: Adapt to Redis Cluster (#9588)
This commit is contained in:
parent
81f97f6f88
commit
6427337728
12 changed files with 59 additions and 42 deletions
|
|
@ -421,12 +421,12 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
|||
}
|
||||
req.File = downloadPath
|
||||
switch req.Type {
|
||||
case "mysql", "mariadb":
|
||||
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||
if err := backupService.MysqlRecover(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||
if err := backupService.PostgresqlRecover(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
|
|
@ -436,7 +436,7 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
|||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case "redis":
|
||||
case "redis", constant.AppRedisCluster:
|
||||
if err := backupService.RedisRecover(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
|||
// @Tags Database Redis
|
||||
// @Summary Load redis conf
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Param request body dto.LoadRedisStatus true "request"
|
||||
// @Success 200 {object} dto.RedisConf
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /databases/redis/conf [post]
|
||||
func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
var req dto.LoadRedisStatus
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -55,13 +55,13 @@ func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
|||
// @Tags Database Redis
|
||||
// @Summary Load redis persistence conf
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Param request body dto.LoadRedisStatus true "request"
|
||||
// @Success 200 {object} dto.RedisPersistence
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /databases/redis/persistence/conf [post]
|
||||
func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
var req dto.LoadRedisStatus
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ type RedisConfUpdate struct {
|
|||
Timeout string `json:"timeout"`
|
||||
Maxclients string `json:"maxclients"`
|
||||
Maxmemory string `json:"maxmemory"`
|
||||
DBType string `json:"dbType" validate:"required,oneof=redis redis-cluster"`
|
||||
}
|
||||
type RedisConfPersistenceUpdate struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
|
|
@ -181,6 +182,7 @@ type RedisConfPersistenceUpdate struct {
|
|||
Appendonly string `json:"appendonly"`
|
||||
Appendfsync string `json:"appendfsync"`
|
||||
Save string `json:"save"`
|
||||
DBType string `json:"dbType" validate:"required,oneof=redis redis-cluster"`
|
||||
}
|
||||
|
||||
type RedisConf struct {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
)
|
||||
|
||||
func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
|||
}
|
||||
|
||||
func (u *BackupService) RedisRecover(req dto.CommonRecover) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ func (u *BackupService) RedisRecover(req dto.CommonRecover) error {
|
|||
}
|
||||
|
||||
func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDir, fileName, secret, taskID string) error {
|
||||
|
||||
var (
|
||||
err error
|
||||
itemTask *task.Task
|
||||
|
|
@ -102,7 +103,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
|||
}
|
||||
|
||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data/appendonlydir", global.Dir.AppInstallDir, "redis", redisInfo.Name)
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data/appendonlydir", global.Dir.AppInstallDir, redisInfo.Key, redisInfo.Name)
|
||||
if err := fileOp.TarGzCompressPro(true, redisDataDir, path.Join(backupDir, fileName), secret, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -111,14 +112,14 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
|||
if strings.HasSuffix(fileName, ".aof") {
|
||||
stdout1, err := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/appendonly.aof %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
||||
if err != nil {
|
||||
return errors.New(string(stdout1))
|
||||
return errors.New(stdout1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
stdout1, err1 := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/dump.rdb %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
||||
if err1 != nil {
|
||||
return errors.New(string(stdout1))
|
||||
return errors.New(stdout1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -196,12 +197,12 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover
|
|||
}
|
||||
}()
|
||||
}
|
||||
composeDir := fmt.Sprintf("%s/redis/%s", global.Dir.AppInstallDir, redisInfo.Name)
|
||||
composeDir := fmt.Sprintf("%s/%s/%s", global.Dir.AppInstallDir, redisInfo.Key, redisInfo.Name)
|
||||
if _, err := compose.Down(composeDir + "/docker-compose.yml"); err != nil {
|
||||
return err
|
||||
}
|
||||
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") {
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data", global.Dir.AppInstallDir, "redis", redisInfo.Name)
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data", global.Dir.AppInstallDir, redisInfo.Key, redisInfo.Name)
|
||||
if err := fileOp.TarGzExtractPro(recoverFile, redisDataDir, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ type IRedisService interface {
|
|||
ChangePassword(info dto.ChangeRedisPass) error
|
||||
|
||||
LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error)
|
||||
LoadConf(req dto.OperationWithName) (*dto.RedisConf, error)
|
||||
LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error)
|
||||
LoadConf(req dto.LoadRedisStatus) (*dto.RedisConf, error)
|
||||
LoadPersistenceConf(req dto.LoadRedisStatus) (*dto.RedisPersistence, error)
|
||||
|
||||
CheckHasCli() bool
|
||||
InstallCli() error
|
||||
|
|
@ -41,7 +41,7 @@ func NewIRedisService() IRedisService {
|
|||
}
|
||||
|
||||
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Database)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.DBType, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
|||
confs = append(confs, redisConfig{key: "timeout", value: req.Timeout})
|
||||
confs = append(confs, redisConfig{key: "maxclients", value: req.Maxclients})
|
||||
confs = append(confs, redisConfig{key: "maxmemory", value: req.Maxmemory})
|
||||
if err := confSet(redisInfo.Name, "", confs); err != nil {
|
||||
if err := confSet(redisInfo.Name, req.DBType, "", confs); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/redis/%s/docker-compose.yml", global.Dir.AppInstallDir, redisInfo.Name)); err != nil {
|
||||
|
|
@ -107,7 +107,7 @@ func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
|||
}
|
||||
|
||||
func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Database)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.DBType, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -119,10 +119,10 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate)
|
|||
confs = append(confs, redisConfig{key: "appendonly", value: req.Appendonly})
|
||||
confs = append(confs, redisConfig{key: "appendfsync", value: req.Appendfsync})
|
||||
}
|
||||
if err := confSet(redisInfo.Name, req.Type, confs); err != nil {
|
||||
if err := confSet(redisInfo.Name, req.DBType, req.Type, confs); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/redis/%s/docker-compose.yml", global.Dir.AppInstallDir, redisInfo.Name)); err != nil {
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", global.Dir.AppInstallDir, req.DBType, redisInfo.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -157,8 +157,8 @@ func (u *RedisService) LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, er
|
|||
return &info, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadConf(req dto.LoadRedisStatus) (*dto.RedisConf, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -174,8 +174,8 @@ func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, erro
|
|||
return &item, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadPersistenceConf(req dto.LoadRedisStatus) (*dto.RedisPersistence, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -214,8 +214,8 @@ type redisConfig struct {
|
|||
value string
|
||||
}
|
||||
|
||||
func confSet(redisName string, updateType string, changeConf []redisConfig) error {
|
||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", global.Dir.AppInstallDir, redisName)
|
||||
func confSet(redisName string, redisType string, updateType string, changeConf []redisConfig) error {
|
||||
path := fmt.Sprintf("%s/%s/%s/conf/redis.conf", global.Dir.AppInstallDir, redisType, redisName)
|
||||
lineBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ export namespace Database {
|
|||
appendonly: string;
|
||||
appendfsync: string;
|
||||
save: string;
|
||||
dbType: string;
|
||||
}
|
||||
export interface RedisStatus {
|
||||
tcp_port: string;
|
||||
|
|
|
|||
|
|
@ -78,8 +78,9 @@ export const getAppInstalledByID = (installID: number, node?: string) => {
|
|||
return http.get<App.AppInstalledInfo>(`apps/installed/info/${installID}${params}`);
|
||||
};
|
||||
|
||||
export const installedOp = (op: App.AppInstalledOp) => {
|
||||
return http.post<any>('apps/installed/op', op, TimeoutEnum.T_40S);
|
||||
export const installedOp = (op: App.AppInstalledOp, node?: string) => {
|
||||
const params = node ? `?operateNode=${node}` : '';
|
||||
return http.post<any>(`apps/installed/op${params}`, op, TimeoutEnum.T_40S);
|
||||
};
|
||||
|
||||
export const syncInstalledApp = () => {
|
||||
|
|
|
|||
|
|
@ -111,11 +111,14 @@ export const loadRemoteAccess = (type: string, database: string) => {
|
|||
export const loadRedisStatus = (type: string, database: string) => {
|
||||
return http.post<Database.RedisStatus>(`/databases/redis/status`, { type: type, name: database });
|
||||
};
|
||||
export const loadRedisConf = (database: string) => {
|
||||
return http.post<Database.RedisConf>(`/databases/redis/conf`, { name: database });
|
||||
export const loadRedisConf = (type: string, database: string) => {
|
||||
return http.post<Database.RedisConf>(`/databases/redis/conf`, { type: type, name: database });
|
||||
};
|
||||
export const redisPersistenceConf = (database: string) => {
|
||||
return http.post<Database.RedisPersistenceConf>(`/databases/redis/persistence/conf`, { name: database });
|
||||
export const redisPersistenceConf = (type: string, database: string) => {
|
||||
return http.post<Database.RedisPersistenceConf>(`/databases/redis/persistence/conf`, {
|
||||
type: type,
|
||||
name: database,
|
||||
});
|
||||
};
|
||||
export const checkRedisCli = () => {
|
||||
return http.get<boolean>(`/databases/redis/check`);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const jumpToInstall = (type: string, key: string) => {
|
|||
case 'redis-cluster':
|
||||
jumpToPath(router, '/xpack/cluster/redis');
|
||||
return true;
|
||||
case 'postgres-cluster':
|
||||
case 'postgresql-cluster':
|
||||
jumpToPath(router, '/xpack/cluster/postgres');
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<LayoutContent title="Redis">
|
||||
<template #app v-if="currentDB?.from === 'local'">
|
||||
<AppStatus
|
||||
:app-key="'redis'"
|
||||
:app-key="currentDB.type"
|
||||
:app-name="appName"
|
||||
v-model:loading="loading"
|
||||
@before="onBefore"
|
||||
|
|
|
|||
|
|
@ -174,7 +174,11 @@ const changeTab = (val: string) => {
|
|||
loadConfFile();
|
||||
break;
|
||||
case 'persistence':
|
||||
persistenceRef.value!.acceptParams({ status: redisStatus.value, database: database.value });
|
||||
persistenceRef.value!.acceptParams({
|
||||
status: redisStatus.value,
|
||||
database: database.value,
|
||||
type: dbType.value,
|
||||
});
|
||||
break;
|
||||
case 'tuning':
|
||||
case 'port':
|
||||
|
|
@ -228,7 +232,7 @@ const onChangePort = async (formEl: FormInstance | undefined) => {
|
|||
return;
|
||||
}
|
||||
let params = {
|
||||
key: 'redis',
|
||||
key: dbType.value,
|
||||
name: form.name,
|
||||
port: form.port,
|
||||
};
|
||||
|
|
@ -298,7 +302,7 @@ const onSaveFile = async () => {
|
|||
};
|
||||
const submitFile = async () => {
|
||||
let param = {
|
||||
type: 'redis',
|
||||
type: dbType.value,
|
||||
database: database.value,
|
||||
file: redisConf.value,
|
||||
};
|
||||
|
|
@ -315,7 +319,7 @@ const submitFile = async () => {
|
|||
};
|
||||
|
||||
const loadForm = async () => {
|
||||
const res = await loadRedisConf(database.value);
|
||||
const res = await loadRedisConf(dbType.value, database.value);
|
||||
form.name = res.data?.name;
|
||||
form.timeout = Number(res.data?.timeout);
|
||||
form.maxclients = Number(res.data?.maxclients);
|
||||
|
|
|
|||
|
|
@ -145,13 +145,16 @@ const rules = reactive({
|
|||
const formRef = ref<FormInstance>();
|
||||
const database = ref();
|
||||
const opRef = ref();
|
||||
const dbType = ref('redis');
|
||||
|
||||
interface DialogProps {
|
||||
database: string;
|
||||
status: string;
|
||||
type: string;
|
||||
}
|
||||
const persistenceShow = ref(false);
|
||||
const acceptParams = (prop: DialogProps): void => {
|
||||
dbType.value = prop.type;
|
||||
persistenceShow.value = true;
|
||||
database.value = prop.database;
|
||||
if (prop.status === 'Running') {
|
||||
|
|
@ -197,7 +200,7 @@ const search = async () => {
|
|||
};
|
||||
const onBackup = async () => {
|
||||
emit('loading', true);
|
||||
await handleBackup({ name: database.value, detailName: '', type: 'redis', secret: '', taskID: '' })
|
||||
await handleBackup({ name: database.value, detailName: '', type: dbType.value, secret: '', taskID: '' })
|
||||
.then(() => {
|
||||
emit('loading', false);
|
||||
search();
|
||||
|
|
@ -210,7 +213,7 @@ const onBackup = async () => {
|
|||
const onRecover = async () => {
|
||||
let param = {
|
||||
downloadAccountID: currentRow.value.downloadAccountID,
|
||||
type: 'redis',
|
||||
type: dbType.value,
|
||||
name: database.value,
|
||||
detailName: '',
|
||||
file: currentRow.value.fileDir + '/' + currentRow.value.fileName,
|
||||
|
|
@ -283,6 +286,7 @@ const onSave = async (formEl: FormInstance | undefined, type: string) => {
|
|||
param.type = type;
|
||||
param.appendfsync = form.appendfsync;
|
||||
param.appendonly = form.appendonly;
|
||||
param.dbType = dbType.value;
|
||||
emit('loading', true);
|
||||
await updateRedisPersistenceConf(param)
|
||||
.then(() => {
|
||||
|
|
@ -305,6 +309,7 @@ const onSave = async (formEl: FormInstance | undefined, type: string) => {
|
|||
}
|
||||
param.type = type;
|
||||
param.save = itemSaves.join(',');
|
||||
param.dbType = dbType.value;
|
||||
emit('loading', true);
|
||||
await updateRedisPersistenceConf(param)
|
||||
.then(() => {
|
||||
|
|
@ -318,7 +323,7 @@ const onSave = async (formEl: FormInstance | undefined, type: string) => {
|
|||
|
||||
const loadform = async () => {
|
||||
form.saves = [];
|
||||
const res = await redisPersistenceConf(database.value);
|
||||
const res = await redisPersistenceConf(dbType.value, database.value);
|
||||
form.appendonly = res.data?.appendonly;
|
||||
form.appendfsync = res.data?.appendfsync;
|
||||
let itemSaves = res.data?.save.split(' ');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue