diff --git a/agent/middleware/certificate.go b/agent/middleware/certificate.go index 700003a5b..09ee10b57 100644 --- a/agent/middleware/certificate.go +++ b/agent/middleware/certificate.go @@ -6,6 +6,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/api/v2/helper" "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/gin-gonic/gin" ) @@ -24,6 +25,12 @@ func Certificate() gin.HandlerFunc { helper.InternalServer(c, fmt.Errorf("err certificate")) return } + masterProxyID := c.Request.Header.Get("Proxy-ID") + proxyID, err := cmd.RunDefaultWithStdoutBashC("cat /etc/1panel/.nodeProxyID") + if err == nil && len(proxyID) != 0 && proxyID != masterProxyID { + helper.InternalServer(c, fmt.Errorf("err proxy id")) + return + } c.Next() } } diff --git a/agent/utils/cloud_storage/client/sftp.go b/agent/utils/cloud_storage/client/sftp.go index aad863404..b1e9d179f 100644 --- a/agent/utils/cloud_storage/client/sftp.go +++ b/agent/utils/cloud_storage/client/sftp.go @@ -79,13 +79,15 @@ func (s sftpClient) Upload(src, target string) (bool, error) { defer srcFile.Close() targetDir, _ := path.Split(target) - if _, err = client.Stat(targetDir); err != nil { - if os.IsNotExist(err) { - if err = client.MkdirAll(targetDir); err != nil { + if len(targetDir) != 0 { + if _, err = client.Stat(targetDir); err != nil { + if os.IsNotExist(err) { + if err = client.MkdirAll(targetDir); err != nil { + return false, err + } + } else { return false, err } - } else { - return false, err } } dstFile, err := client.Create(target) diff --git a/agent/utils/files/file_op.go b/agent/utils/files/file_op.go index a3fab7ac7..7e6c7040a 100644 --- a/agent/utils/files/file_op.go +++ b/agent/utils/files/file_op.go @@ -827,7 +827,7 @@ func (f FileOp) TarGzCompressPro(withDir bool, src, dst, secret, exclusionRules if len(secret) != 0 { commands = fmt.Sprintf("tar %s -zcf - %s | openssl enc -aes-256-cbc -salt -k '%s' -out %s", exStr, srcItem, secret, dst) - global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******")) + global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" '%s' ", secret), " ****** ")) } else { commands = fmt.Sprintf("tar -zcf %s %s %s", dst, exStr, srcItem) global.LOG.Debug(commands) @@ -850,7 +850,7 @@ func (f FileOp) TarGzFilesWithCompressPro(list []string, dst, secret string) err commands := "" if len(secret) != 0 { commands = fmt.Sprintf("tar -zcf - %s | openssl enc -aes-256-cbc -salt -k '%s' -out %s", strings.Join(filelist, " "), secret, dst) - global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******")) + global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" '%s' ", secret), " ****** ")) } else { commands = fmt.Sprintf("tar -zcf %s %s", dst, strings.Join(filelist, " ")) global.LOG.Debug(commands) @@ -869,7 +869,7 @@ func (f FileOp) TarGzExtractPro(src, dst string, secret string) error { commands := "" if len(secret) != 0 { commands = fmt.Sprintf("openssl enc -d -aes-256-cbc -salt -k '%s' -in %s | tar -zxf - > /root/log", secret, src) - global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******")) + global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" '%s' ", secret), " ****** ")) } else { commands = fmt.Sprintf("tar zxvf %s", src) global.LOG.Debug(commands) diff --git a/agent/utils/files/tar_gz.go b/agent/utils/files/tar_gz.go index d9dfadd48..83d36bd39 100644 --- a/agent/utils/files/tar_gz.go +++ b/agent/utils/files/tar_gz.go @@ -47,7 +47,7 @@ func (t TarGzArchiver) Compress(sourcePaths []string, dstFile string, secret str if len(secret) != 0 { extraCmd := fmt.Sprintf("| openssl enc -aes-256-cbc -salt -k '%s' -out '%s'", secret, dstFile) commands = fmt.Sprintf("tar -zcf - -C \"%s\" %s %s", aheadDir, itemDir, extraCmd) - global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******")) + global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" '%s' ", secret), " ****** ")) } else { commands = fmt.Sprintf("tar -zcf \"%s\" -C \"%s\" %s", dstFile, aheadDir, itemDir) global.LOG.Debug(commands) diff --git a/core/app/task/task.go b/core/app/task/task.go index c3d1ddc7d..4f2b6a1cc 100644 --- a/core/app/task/task.go +++ b/core/app/task/task.go @@ -51,6 +51,7 @@ const ( TaskRsync = "TaskRsync" TaskInstallCluster = "TaskInstallCluster" TaskCreateCluster = "TaskCreateCluster" + TaskBackup = "TaskBackup" ) const ( diff --git a/core/i18n/lang/en.yaml b/core/i18n/lang/en.yaml index d1b8d073f..07b00ac8e 100644 --- a/core/i18n/lang/en.yaml +++ b/core/i18n/lang/en.yaml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} failed: {{ .err }}" TaskInstall: "Install" TaskUpgrade: "Upgrade" TaskSync: 'Synchronize' +TaskBackup: "Backup" SuccessStatus: "{{ .name }} succeeded" FailedStatus: "{{ .name }} failed {{ .err }}" Start: "Start" SubTask: "Subtask" +Skip: "Skip errors and continue..." #script ScriptLibrary: "Script Library" @@ -119,6 +121,11 @@ UploadUpgradeFile: "Distribute upgrade files" RestartAfterUpgrade: "Start service after upgrade" #add node +MasterData: "Master Node Data" +LoadSftpClient: "Load SFTP Client" +PackageMasterData: "Generate master node backup package" +UploadBackup: "Upload backup data" +MvBackup: "Move data to backup directory" TaskAddNode: "Add node" LoadNodeArch: "Get node architecture info" LoadNodeArchDetail: "Detected master node architecture: {{ .local }}, child node architecture: {{ .node }}" diff --git a/core/i18n/lang/ja.yaml b/core/i18n/lang/ja.yaml index 2421cdad4..278e4830d 100644 --- a/core/i18n/lang/ja.yaml +++ b/core/i18n/lang/ja.yaml @@ -88,10 +88,12 @@ SubTaskFailed: "{{ .name }} 失敗: {{ .err }}" TaskInstall: "インストール" TaskUpgrade: "アップグレード" TaskSync: '同期' +TaskBackup: "バックアップ" SuccessStatus: "{{ .name }} 成功" FailedStatus: "{{ .name }} 失敗 {{ .err }}" Start: "開始" SubTask: "サブタスク" +Skip: "エラーを無視して続行..." #script ScriptLibrary: "スクリプトライブラリ" @@ -120,6 +122,11 @@ UploadUpgradeFile: "アップグレードに必要なファイルを配布" RestartAfterUpgrade: "アップグレード後にサービスを起動" #add node +MasterData: "マスターノードデータ" +LoadSftpClient: "SFTPクライアントの取得" +PackageMasterData: "マスターノードのバックアップパッケージを生成" +UploadBackup: "バックアップデータをアップロード" +MvBackup: "データをバックアップディレクトリに移動" TaskAddNode: "ノードを追加" LoadNodeArch: "ノードアーキテクチャ情報を取得" LoadNodeArchDetail: "検出されたマスターノードアーキテクチャ: {{ .local }}, 子ノードアーキテクチャ: {{ .node }}" diff --git a/core/i18n/lang/ko.yaml b/core/i18n/lang/ko.yaml index b5a37712d..ced2d8f3e 100644 --- a/core/i18n/lang/ko.yaml +++ b/core/i18n/lang/ko.yaml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} 실패: {{ .err }}" TaskInstall: "설치" TaskUpgrade: "업그레이드" TaskSync: '동기화' +TaskBackup: "백업" SuccessStatus: "{{ .name }} 성공" FailedStatus: "{{ .name }} 실패 {{ .err }}" Start: "시작" SubTask: "서브 작업" +Skip: "오류 무시하고 계속..." #script ScriptLibrary: "스크립트 라이브러리" @@ -119,6 +121,11 @@ UploadUpgradeFile: "업그레이드에 필요한 파일 전송" RestartAfterUpgrade: "업그레이드 후 서비스 시작" #add node +MasterData: "마스터 노드 데이터" +LoadSftpClient: "SFTP 클라이언트 가져오기" +PackageMasterData: "마스터 노드 백업 패키지 생성" +UploadBackup: "백업 데이터 업로드" +MvBackup: "데이터를 백업 디렉터리로 이동" TaskAddNode: "노드 추가" LoadNodeArch: "노드 아키텍처 정보 가져오기" LoadNodeArchDetail: "감지된 마스터 노드 아키텍처: {{ .local }}, 자식 노드 아키텍처: {{ .node }}" diff --git a/core/i18n/lang/ms.yml b/core/i18n/lang/ms.yml index a6ebb80ae..3668b459e 100644 --- a/core/i18n/lang/ms.yml +++ b/core/i18n/lang/ms.yml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} gagal: {{ .err }}" TaskInstall: "Pasang" TaskUpgrade: "Kemas kini" TaskSync: 'Selaraskan' +TaskBackup: "Sandaran" SuccessStatus: "{{ .name }} berjaya" FailedStatus: "{{ .name }} gagal {{ .err }}" Start: "Mula" SubTask: "Tugas Sub" +Skip: "Abaikan ralat dan teruskan..." #script ScriptLibrary: "Pustaka Skrip" @@ -119,6 +121,11 @@ UploadUpgradeFile: "Sebarkan fail naik taraf" RestartAfterUpgrade: "Mulakan perkhidmatan selepas naik taraf" #add node +MasterData: "Data Nod Master" +LoadSftpClient: "Dapatkan Klien SFTP" +PackageMasterData: "Hasilkan pakej sandaran nod master" +UploadBackup: "Muat naik data sandaran" +MvBackup: "Alihkan data ke direktori sandaran" TaskAddNode: "Tambah nod" LoadNodeArch: "Dapatkan maklumat seni bina nod" LoadNodeArchDetail: "Mengesan seni bina nod induk: {{ .local }}, seni bina nod anak: {{ .node }}" diff --git a/core/i18n/lang/pt-BR.yaml b/core/i18n/lang/pt-BR.yaml index 61a53076d..27c2e9709 100644 --- a/core/i18n/lang/pt-BR.yaml +++ b/core/i18n/lang/pt-BR.yaml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} falhou: {{ .err }}" TaskInstall: "Instalar" TaskUpgrade: "Atualizar" TaskSync: 'Sincronizar' +TaskBackup: "Backup" SuccessStatus: "{{ .name }} bem-sucedido" FailedStatus: "{{ .name }} falhou {{ .err }}" Start: "Iniciar" SubTask: "Subtarefa" +Skip: "Ignorar erros e continuar..." #script ScriptLibrary: "Biblioteca de Scripts" @@ -119,6 +121,11 @@ UploadUpgradeFile: "Distribuir arquivos necessários para a atualização" RestartAfterUpgrade: "Iniciar serviço após a atualização" #add node +MasterData: "Dados do Nó Mestre" +LoadSftpClient: "Carregar Cliente SFTP" +PackageMasterData: "Gerar pacote de backup do nó mestre" +UploadBackup: "Carregar dados de backup" +MvBackup: "Mover dados para diretório de backup" TaskAddNode: "Adicionar nó" LoadNodeArch: "Obter informações de arquitetura do nó" LoadNodeArchDetail: "Arquitetura do nó mestre detectada: {{ .local }}, arquitetura do nó filho: {{ .node }}" diff --git a/core/i18n/lang/ru.yaml b/core/i18n/lang/ru.yaml index 287d4d29e..044f314c8 100644 --- a/core/i18n/lang/ru.yaml +++ b/core/i18n/lang/ru.yaml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} не удалось: {{ .err }}" TaskInstall: "Установить" TaskUpgrade: "Обновить" TaskSync: 'Синхронизация' +TaskBackup: "Резервная копия" SuccessStatus: "{{ .name }} успешно" FailedStatus: "{{ .name }} не удалось {{ .err }}" Start: "Начать" SubTask: "Подзадача" +Skip: "Пропустить ошибки и продолжить..." #script ScriptLibrary: "Библиотека скриптов" @@ -119,6 +121,11 @@ UploadUpgradeFile: "Распределение файлов обновления RestartAfterUpgrade: "Запуск службы после обновления" #add node +MasterData: "Данные главного узла" +LoadSftpClient: "Загрузить SFTP-клиент" +PackageMasterData: "Создать архив резервной копии главного узла" +UploadBackup: "Загрузить резервные данные" +MvBackup: "Переместить данные в резервный каталог" TaskAddNode: "Добавить узел" LoadNodeArch: "Получить информацию об архитектуре узла" LoadNodeArchDetail: "Обнаружена архитектура главного узла: {{ .local }}, архитектура дочернего узла: {{ .node }}" diff --git a/core/i18n/lang/tr.yaml b/core/i18n/lang/tr.yaml index 3c0d6a827..90f4d55a0 100644 --- a/core/i18n/lang/tr.yaml +++ b/core/i18n/lang/tr.yaml @@ -86,10 +86,12 @@ SubTaskFailed: "{{ .name }} başarısız: {{ .err }}" TaskInstall: "Kurulum" TaskUpgrade: "Yükseltme" TaskSync: 'Senkronize' +TaskBackup: "Yedekleme" SuccessStatus: "{{ .name }} başarılı" FailedStatus: "{{ .name }} başarısız {{ .err }}" Start: "Başla" SubTask: "Alt görev" +Skip: "Hataları atla ve devam et..." #script ScriptLibrary: "Betik Kütüphanesi" @@ -117,6 +119,11 @@ UploadUpgradeFile: "Yükseltme dosyalarını dağıt" RestartAfterUpgrade: "Yükseltme sonrası servisi başlat" #add node +MasterData: "Ana Düğüm Verisi" +LoadSftpClient: "SFTP İstemcisini Yükle" +PackageMasterData: "Ana düğüm yedek paketi oluştur" +UploadBackup: "Yedek verileri yükle" +MvBackup: "Verileri yedek dizinine taşı" TaskAddNode: "Düğüm ekle" LoadNodeArch: "Düğüm mimari bilgilerini al" LoadNodeArchDetail: "Ana düğüm mimarisi tespit edildi: {{ .local }}, alt düğüm mimarisi: {{ .node }}" diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml index c51ab4729..44b86d1cf 100644 --- a/core/i18n/lang/zh-Hant.yaml +++ b/core/i18n/lang/zh-Hant.yaml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} 失敗: {{ .err }}" TaskInstall: "安裝" TaskUpgrade: "升級" TaskSync: '同步' +TaskBackup: "備份" SuccessStatus: "{{ .name }} 成功" FailedStatus: "{{ .name }} 失敗 {{ .err }}" Start: "開始" SubTask: "子任務" +Skip: "忽略錯誤並繼續..." #script ScriptLibrary: "腳本庫" @@ -120,6 +122,11 @@ UploadUpgradeFile: "發送升級所需文件" RestartAfterUpgrade: "升級後啟動服務" #add node +MasterData: "主節點數據" +LoadSftpClient: "獲取上傳客戶端" +PackageMasterData: "生成主節點備份壓縮包" +UploadBackup: "上傳備份數據" +MvBackup: "移動數據到備份目錄" TaskAddNode: "新增節點" LoadNodeArch: "取得節點架構資訊" LoadNodeArchDetail: "檢測到主節點架構: {{ .local }},子節點架構: {{ .node }}" diff --git a/core/i18n/lang/zh.yaml b/core/i18n/lang/zh.yaml index d52d76b7b..3d7ad80af 100644 --- a/core/i18n/lang/zh.yaml +++ b/core/i18n/lang/zh.yaml @@ -87,10 +87,12 @@ SubTaskFailed: "{{ .name }} 失败: {{ .err }}" TaskInstall: "安装" TaskUpgrade: "升级" TaskSync: "同步" +TaskBackup: "备份" SuccessStatus: "{{ .name }} 成功" FailedStatus: "{{ .name }} 失败 {{ .err }}" Start: "开始" SubTask: "子任务" +Skip: "忽略错误并继续..." #script ScriptLibrary: "脚本库" @@ -120,6 +122,9 @@ UploadUpgradeFile: "下发升级所需文件" RestartAfterUpgrade: "升级后启动服务" #add node +MasterData: "主节点数据" +LoadSftpClient: "获取上传客户端" +UploadBackup: "上传备份数据" TaskAddNode: "添加节点" LoadNodeArch: "获取节点架构信息" LoadNodeArchDetail: "检测到主节点架构: {{ .local }},子节点架构: {{ .node }}" diff --git a/core/utils/cloud_storage/client/sftp.go b/core/utils/cloud_storage/client/sftp.go index 04943335d..617b609ea 100644 --- a/core/utils/cloud_storage/client/sftp.go +++ b/core/utils/cloud_storage/client/sftp.go @@ -83,13 +83,15 @@ func (s sftpClient) Upload(src, target string) (bool, error) { targetFilePath := path.Join(s.bucket, target) targetDir, _ := path.Split(targetFilePath) - if _, err = client.Stat(targetDir); err != nil { - if os.IsNotExist(err) { - if err = client.MkdirAll(targetDir); err != nil { + if len(targetDir) != 0 { + if _, err = client.Stat(targetDir); err != nil { + if os.IsNotExist(err) { + if err = client.MkdirAll(targetDir); err != nil { + return false, err + } + } else { return false, err } - } else { - return false, err } } dstFile, err := client.Create(path.Join(s.bucket, target)) diff --git a/core/utils/files/files.go b/core/utils/files/files.go index f59e26ea7..dfae19929 100644 --- a/core/utils/files/files.go +++ b/core/utils/files/files.go @@ -110,7 +110,7 @@ func HandleTar(sourceDir, targetDir, name, exclusionRules string, secret string) if len(secret) != 0 { extraCmd := "| openssl enc -aes-256-cbc -salt -k '" + secret + "' -out" commands = fmt.Sprintf("tar -zcf %s %s %s %s", " -"+excludeRules, path, extraCmd, targetDir+"/"+name) - global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******")) + global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" '%s' ", secret), " ****** ")) } else { commands = fmt.Sprintf("tar -zcf %s %s %s", targetDir+"/"+name, excludeRules, path) global.LOG.Debug(commands) @@ -136,7 +136,7 @@ func HandleUnTar(sourceFile, targetDir string, secret string) error { if len(secret) != 0 { extraCmd := "openssl enc -d -aes-256-cbc -k '" + secret + "' -in " + sourceFile + " | " commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1") - global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******")) + global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" '%s' ", secret), " ****** ")) } else { commands = fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir) global.LOG.Debug(commands) diff --git a/core/utils/ssh/ssh.go b/core/utils/ssh/ssh.go index 172ee004a..6abf38c40 100644 --- a/core/utils/ssh/ssh.go +++ b/core/utils/ssh/ssh.go @@ -20,7 +20,8 @@ type ConnInfo struct { } type SSHClient struct { - Client *gossh.Client `json:"client"` + Client *gossh.Client `json:"client"` + SudoItem string `json:"sudoItem"` } func NewClient(c ConnInfo) (*SSHClient, error) { @@ -54,10 +55,16 @@ func NewClient(c ConnInfo) (*SSHClient, error) { if nil != err { return nil, err } - return &SSHClient{Client: client}, nil + sshClient := &SSHClient{Client: client} + if _, err := sshClient.Run("sudo -n ls"); err == nil { + sshClient.SudoItem = "sudo" + } + return sshClient, nil } func (c *SSHClient) Run(shell string) (string, error) { + shell = c.SudoItem + " " + shell + shell = strings.ReplaceAll(shell, " && ", fmt.Sprintf(" && %s ", c.SudoItem)) session, err := c.Client.NewSession() if err != nil { return "", err @@ -84,6 +91,8 @@ func (c *SSHClient) IsRoot(user string) bool { } func (c *SSHClient) Runf(shell string, args ...interface{}) (string, error) { + shell = c.SudoItem + " " + shell + shell = strings.ReplaceAll(shell, " && ", fmt.Sprintf(" && %s ", c.SudoItem)) session, err := c.Client.NewSession() if err != nil { return "", err diff --git a/frontend/src/components/complex-table/index.vue b/frontend/src/components/complex-table/index.vue index d4f129238..3e31005d2 100644 --- a/frontend/src/components/complex-table/index.vue +++ b/frontend/src/components/complex-table/index.vue @@ -36,7 +36,11 @@ @size-change="sizeChange" @current-change="currentChange" :size="mobile || paginationConfig.small ? 'small' : 'default'" - :layout="mobile ? 'total, prev, pager, next' : 'total, sizes, prev, pager, next, jumper'" + :layout=" + mobile || paginationConfig.small + ? 'total, prev, pager, next' + : 'total, sizes, prev, pager, next, jumper' + " /> diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 4e17280e0..8b4d97c7d 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -3371,6 +3371,12 @@ const message = { }, node: { master: 'Main Node', + masterBackup: 'Master Node Backup', + backupNode: 'Backup Node', + backupFrequency: 'Backup Frequency (hours)', + backupCopies: 'Backup Retention Copies', + masterBackupAlert: + 'Master node backup is not currently configured. To ensure data security, please set up a backup node as soon as possible to facilitate manual switching to a new master node in case of failure.', node: 'Node', addr: 'Address', nodeUnhealthy: 'Node status abnormal', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index d18787cc3..c2c69cae7 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -3240,6 +3240,12 @@ const message = { }, node: { master: '主ノード', + masterBackup: 'マスターノードバックアップ', + backupNode: 'バックアップノード', + backupFrequency: 'バックアップ頻度(時間)', + backupCopies: 'バックアップ保持数', + masterBackupAlert: + '現在マスターノードのバックアップが設定されていません。データセキュリティを確保するため、障害時に新しいマスターノードに手動で切り替えられるよう、速やかにバックアップノードを設定してください。', node: 'ノード', addr: 'アドレス', nodeUnhealthy: 'ノード状態異常', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 905a0d86c..743a9305a 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -3182,6 +3182,12 @@ const message = { }, node: { master: '주 노드', + masterBackup: '마스터 노드 백업', + backupNode: '백업 노드', + backupFrequency: '백업 주기(시간)', + backupCopies: '백업 기록 보관 수', + masterBackupAlert: + '현재 마스터 노드 백업이 구성되지 않았습니다. 데이터 보안을 위해 장애 시 새로운 마스터 노드로 수동 전환이 가능하도록 가능한 빨리 백업 노드를 설정하십시오.', node: '노드', addr: '주소', nodeUnhealthy: '노드 상태 이상', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 9395406d4..76ad9802f 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -3311,6 +3311,12 @@ const message = { }, node: { master: 'Nod Utama', + masterBackup: 'Sandaran Nod Master', + backupNode: 'Nod Sandaran', + backupFrequency: 'Kekerapan Sandaran (jam)', + backupCopies: 'Bilangan salinan sandaran yang disimpan', + masterBackupAlert: + 'Sandaran nod master belum dikonfigurasikan. Untuk memastikan keselamatan data, sila sediakan nod sandaran secepat mungkin untuk memudahkan pertukaran manual ke nod master baru sekiranya berlaku kegagalan.', node: 'Nod', addr: 'Alamat', nodeUnhealthy: 'Status nod tidak normal', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index e0d2766e6..6dd94dba5 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -3319,6 +3319,12 @@ const message = { }, node: { master: 'Nó Principal', + masterBackup: 'Backup do Nó Mestre', + backupNode: 'Nó de Backup', + backupFrequency: 'Frequência de Backup (horas)', + backupCopies: 'Número de cópias de backup a reter', + masterBackupAlert: + 'O backup do nó mestre não está configurado atualmente. Para garantir a segurança dos dados, configure um nó de backup o mais rápido possível para facilitar a troca manual para um novo nó mestre em caso de falha.', node: 'Nó', addr: 'Endereço', nodeUnhealthy: 'Estado do nó anormal', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index eb8048f8d..476a41873 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -3304,6 +3304,12 @@ const message = { }, node: { master: 'Главный узел', + masterBackup: 'Резервная копия главного узла', + backupNode: 'Резервный узел', + backupFrequency: 'Частота резервного копирования (часы)', + backupCopies: 'Количество сохраняемых резервных копий', + masterBackupAlert: + 'Резервное копирование главного узла не настроено. Для обеспечения безопасности данных, пожалуйста, настройте резервный узел как можно скорее, чтобы можно было вручную переключиться на новый главный узел в случае сбоя.', node: 'Узел', addr: 'Адрес', nodeUnhealthy: 'Некорректное состояние узла', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 28214182b..4c4dfb10b 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -3406,6 +3406,12 @@ const message = { }, node: { master: 'Ana Düğüm', + masterBackup: 'Ana Düğüm Yedekleme', + backupNode: 'Yedek Düğüm', + backupFrequency: 'Yedekleme Sıklığı (saat)', + backupCopies: 'Saklanacak yedek kopya sayısı', + masterBackupAlert: + 'Ana düğüm yedeklemesi şu anda yapılandırılmamış. Veri güvenliği için, lütfen arıza durumunda yeni bir ana düğüme manuel geçiş yapabilmek amacıyla en kısa sürede bir yedek düğüm ayarlayın.', node: 'Düğüm', addr: 'Adres', nodeUnhealthy: 'Düğüm durumu anormal', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index c3e7f724c..c2d5c9270 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -3138,6 +3138,12 @@ const message = { }, node: { master: '主節點', + masterBackup: '主節點備份', + backupNode: '備份節點', + backupFrequency: '備份頻率(小時)', + backupCopies: '備份記錄保留份數', + masterBackupAlert: + '當前未配置主節點備份,為保障數據安全,請盡快設置備份節點,便於主節點故障時可人工切換新主節點。', node: '節點', addr: '地址', nodeUnhealthy: '節點狀態異常', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index c42f6e1f3..718726977 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -3108,6 +3108,12 @@ const message = { }, node: { master: '主节点', + masterBackup: '主节点备份', + backupNode: '备份节点', + backupFrequency: '备份频率(小时)', + backupCopies: '备份记录保留份数', + masterBackupAlert: + '当前未配置主节点备份,为保障数据安全,请尽快设置备份节点,便于主节点故障时可人工切换新主节点。', node: '节点', addr: '地址', nodeUnhealthy: '节点状态异常',