mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 08:00:53 +00:00
feat: MySQL backup supports custom parameters (#11575)
This commit is contained in:
@@ -65,12 +65,13 @@ type UploadForRecover struct {
|
||||
}
|
||||
|
||||
type CommonBackup struct {
|
||||
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"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
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"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type CronjobOperate struct {
|
||||
Timeout uint `json:"timeout" validate:"number,min=1"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
@@ -123,6 +124,7 @@ type CronjobInfo struct {
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Status string `json:"status"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
}
|
||||
@@ -162,6 +164,7 @@ type CronjobTrans struct {
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
SnapshotRule SnapshotTransHelper `json:"snapshotRule"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
SourceAccounts []string `json:"sourceAccounts"`
|
||||
DownloadAccount string `json:"downloadAccount"`
|
||||
|
||||
@@ -37,6 +37,7 @@ type Cronjob struct {
|
||||
Timeout uint `json:"timeout"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
RetainCopies uint64 `json:"retainCopies"`
|
||||
Args string `json:"args"`
|
||||
|
||||
IsExecuting bool `json:"isExecuting"`
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -44,7 +44,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName, Args: req.Args}
|
||||
if err := handleMysqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID, req.Secret); err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return err
|
||||
@@ -87,7 +87,12 @@ func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint,
|
||||
}
|
||||
}
|
||||
|
||||
itemHandler := func() error { return doMysqlBackup(db, targetDir, fileName, secret) }
|
||||
itemHandler := func() error {
|
||||
if len(db.Args) != 0 {
|
||||
backupTask.Logf("args: %v", db.Args)
|
||||
}
|
||||
return doMysqlBackup(db, targetDir, fileName, secret)
|
||||
}
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
@@ -225,6 +230,7 @@ func doMysqlBackup(db DatabaseHelper, targetDir, fileName, secret string) error
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
Args: db.Args,
|
||||
}
|
||||
if err := cli.Backup(backupInfo); err != nil {
|
||||
return err
|
||||
|
||||
@@ -143,6 +143,7 @@ func (u *CronjobService) Export(req dto.OperateByIDs) (string, error) {
|
||||
Timeout: cronjob.Timeout,
|
||||
IgnoreErr: cronjob.IgnoreErr,
|
||||
Secret: cronjob.Secret,
|
||||
Args: cronjob.Args,
|
||||
}
|
||||
switch cronjob.Type {
|
||||
case "app":
|
||||
@@ -237,6 +238,7 @@ func (u *CronjobService) Import(req []dto.CronjobTrans) error {
|
||||
Timeout: item.Timeout,
|
||||
IgnoreErr: item.IgnoreErr,
|
||||
Secret: item.Secret,
|
||||
Args: item.Args,
|
||||
}
|
||||
hasNotFound := false
|
||||
switch item.Type {
|
||||
@@ -733,6 +735,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
||||
upMap["timeout"] = req.Timeout
|
||||
upMap["ignore_err"] = req.IgnoreErr
|
||||
upMap["secret"] = req.Secret
|
||||
upMap["args"] = req.Args
|
||||
err = cronjobRepo.Update(id, upMap)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -379,6 +379,7 @@ type DatabaseHelper struct {
|
||||
DBType string
|
||||
Database string
|
||||
Name string
|
||||
Args []string
|
||||
}
|
||||
|
||||
func addSkipTask(source string, taskItem *task.Task) {
|
||||
@@ -400,6 +401,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysql.Database,
|
||||
Name: mysql.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@@ -410,6 +412,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: pg.PostgresqlName,
|
||||
Name: pg.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -425,6 +428,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysqlItem.MysqlName,
|
||||
Name: mysqlItem.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
} else {
|
||||
pgItem, _ := postgresqlRepo.Get(repo.WithByID(uint(itemID)))
|
||||
@@ -433,6 +437,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: pgItem.PostgresqlName,
|
||||
Name: pgItem.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ func InitAgentDB() {
|
||||
migrations.AddisIPtoWebsiteSSL,
|
||||
migrations.InitPingStatus,
|
||||
migrations.UpdateApp,
|
||||
migrations.AddCronjobArgs,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -807,3 +807,10 @@ var UpdateApp = &gormigrate.Migration{
|
||||
return tx.AutoMigrate(&model.App{})
|
||||
},
|
||||
}
|
||||
|
||||
var AddCronjobArgs = &gormigrate.Migration{
|
||||
ID: "20260106-add-cronjob-args",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.Cronjob{})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,12 +72,13 @@ type AccessChangeInfo struct {
|
||||
}
|
||||
|
||||
type BackupInfo struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Format string `json:"format"`
|
||||
TargetDir string `json:"targetDir"`
|
||||
FileName string `json:"fileName"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Format string `json:"format"`
|
||||
TargetDir string `json:"targetDir"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
@@ -237,9 +237,17 @@ func (r *Local) Backup(info BackupInfo) error {
|
||||
if r.Type == constant.AppMariaDB {
|
||||
dumpCmd = "mariadb-dump"
|
||||
}
|
||||
global.LOG.Infof("start to %s | gzip > %s.gzip", dumpCmd, info.TargetDir+"/"+info.FileName)
|
||||
global.LOG.Infof("start to %s | gzip > %s.gzip, args: %v", dumpCmd, info.TargetDir+"/"+info.FileName, info.Args)
|
||||
|
||||
cmd := exec.Command("docker", "exec", r.ContainerName, dumpCmd, "--routines", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||
args := []string{"exec", r.ContainerName, dumpCmd, "--routines", "-uroot", "-p" + r.Password, "--default-character-set=" + info.Format}
|
||||
for _, arg := range info.Args {
|
||||
if len(arg) == 0 {
|
||||
continue
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
args = append(args, info.Name)
|
||||
cmd := exec.Command("docker", args...)
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@ export namespace Cronjob {
|
||||
alertMethodItems: Array<string>;
|
||||
|
||||
scopes: string[];
|
||||
args: string;
|
||||
argItems: Array<string>;
|
||||
}
|
||||
export interface Item {
|
||||
val: string;
|
||||
@@ -113,6 +115,7 @@ export namespace Cronjob {
|
||||
alertMethod: string;
|
||||
|
||||
scopes?: string[];
|
||||
args: string;
|
||||
}
|
||||
export interface CronjobTrans {
|
||||
name: string;
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
<DialogPro
|
||||
v-model="open"
|
||||
:title="isBackup ? $t('commons.button.backup') : $t('commons.button.recover') + ' - ' + name"
|
||||
size="small"
|
||||
@close="handleBackupClose"
|
||||
>
|
||||
<el-alert :closable="false">
|
||||
@@ -110,6 +109,17 @@
|
||||
<el-form-item :label="$t('setting.compressPassword')">
|
||||
<el-input v-model="secret" :placeholder="$t('setting.backupRecoverMessage')" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="type === 'mysql' || type === 'mysql-cluster'" :label="$t('cronjob.backupArgs')">
|
||||
<el-select v-model="args" filterable allow-create multiple>
|
||||
<el-option v-for="item in mysqlArgs" :key="item.arg" :value="item.arg" :label="item.arg">
|
||||
{{ item.arg }}
|
||||
<span class="ml-2">{{ item.description }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span class="input-help">
|
||||
{{ $t('cronjob.backupArgsHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="!isBackup && type !== 'app' && type !== 'website'"
|
||||
:label="$t('cronjob.timeout')"
|
||||
@@ -166,6 +176,7 @@ import { MsgSuccess } from '@/utils/message';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import { routerToFileWithPath } from '@/utils/router';
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
import { mysqlArgs } from '@/views/cronjob/cronjob/helper';
|
||||
const { currentNode } = useGlobalStore();
|
||||
|
||||
const PushApp = defineAsyncComponent(async () => {
|
||||
@@ -178,6 +189,7 @@ const PushApp = defineAsyncComponent(async () => {
|
||||
});
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const args = ref([]);
|
||||
const loading = ref();
|
||||
const opRef = ref();
|
||||
const taskLogRef = ref();
|
||||
@@ -311,6 +323,7 @@ const backup = async () => {
|
||||
secret: secret.value,
|
||||
taskID: taskID,
|
||||
description: description.value,
|
||||
args: args.value,
|
||||
};
|
||||
loading.value = true;
|
||||
await handleBackup(params, node.value)
|
||||
@@ -352,6 +365,7 @@ const recover = async (row?: any) => {
|
||||
const onBackup = async () => {
|
||||
description.value = '';
|
||||
secret.value = '';
|
||||
args.value = [];
|
||||
isBackup.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
@@ -1133,6 +1133,12 @@ const message = {
|
||||
failedRecord: 'Failure records',
|
||||
successRecord: 'Successful records',
|
||||
database: 'Backup database',
|
||||
backupArgs: 'Backup Arguments',
|
||||
backupArgsHelper:
|
||||
'Unlisted backup arguments can be manually entered and selected. For example: Enter --no-data and select the first option from the dropdown list.',
|
||||
singleTransaction: 'Backup InnoDB tables using a single transaction, suitable for large-volume data backups',
|
||||
quick: 'Read data row by row instead of loading the entire table into memory, suitable for large-volume data and low-memory machine backups',
|
||||
skipLockTables: 'Backup without locking all tables, suitable for highly concurrent databases',
|
||||
missBackupAccount: 'The backup account could not be found',
|
||||
syncDate: 'Synchronization time ',
|
||||
clean: 'Cache clean',
|
||||
|
||||
@@ -1137,6 +1137,14 @@ const message = {
|
||||
failedRecord: 'Registros fallidos',
|
||||
successRecord: 'Registros completados correctamente',
|
||||
database: 'Respaldo de base de datos',
|
||||
backupArgs: 'Argumentos de Copia de Seguridad',
|
||||
backupArgsHelper:
|
||||
'Los argumentos de copia de seguridad no listados pueden ser ingresados y seleccionados manualmente. Por ejemplo: Ingrese --no-data y seleccione la primera opción de la lista desplegable.',
|
||||
singleTransaction:
|
||||
'Copia de seguridad de tablas InnoDB utilizando una única transacción, adecuada para copias de seguridad de datos de gran volumen',
|
||||
quick: 'Lee datos fila por fila en lugar de cargar la tabla completa en memoria, adecuado para copias de seguridad de datos de gran volumen y máquinas con poca memoria',
|
||||
skipLockTables:
|
||||
'Copia de seguridad sin bloquear todas las tablas, adecuada para bases de datos altamente concurrentes',
|
||||
missBackupAccount: 'No se pudo encontrar la cuenta de respaldo',
|
||||
syncDate: 'Hora de sincronización',
|
||||
clean: 'Limpiar caché',
|
||||
|
||||
@@ -1105,6 +1105,13 @@ const message = {
|
||||
failedRecord: '失敗記録',
|
||||
successRecord: '成功した記録',
|
||||
database: 'バックアップデータベース',
|
||||
backupArgs: 'バックアップ引数',
|
||||
backupArgsHelper:
|
||||
'リストにないバックアップ引数は手動で入力して選択できます。例:--no-data を入力し、ドロップダウンリストの最初のオプションを選択してください。',
|
||||
singleTransaction:
|
||||
'単一トランザクションを使用して InnoDB テーブルをバックアップします。大容量データのバックアップに適しています',
|
||||
quick: 'テーブル全体をメモリにロードする代わりに、データを行単位で読み取ります。大容量データや低メモリマシンのバックアップに適しています',
|
||||
skipLockTables: 'すべてのテーブルをロックせずにバックアップします。高並列データベースに適しています',
|
||||
missBackupAccount: 'バックアップアカウントは見つかりませんでした',
|
||||
syncDate: '同期時間',
|
||||
clean: 'キャッシュクリーン',
|
||||
|
||||
@@ -1091,6 +1091,12 @@ const message = {
|
||||
failedRecord: '실패한 레코드',
|
||||
successRecord: '성공한 레코드',
|
||||
database: '백업 데이터베이스',
|
||||
backupArgs: '백업 인수',
|
||||
backupArgsHelper:
|
||||
'목록에 없는 백업 인수는 수동으로 입력하여 선택할 수 있습니다. 예: --no-data를 입력하고 드롭다운 목록의 첫 번째 옵션을 선택하세요.',
|
||||
singleTransaction: '단일 트랜잭션을 사용하여 InnoDB 테이블을 백업하며, 대용량 데이터 백업에 적합합니다',
|
||||
quick: '전체 테이블을 메모리에 로드하는 대신 데이터를 행별로 읽습니다. 대용량 데이터 및 저메모리 시스템 백업에 적합합니다',
|
||||
skipLockTables: '모든 테이블을 잠그지 않고 백업합니다. 높은 동시성 데이터베이스에 적합합니다',
|
||||
missBackupAccount: '백업 계정을 찾을 수 없습니다',
|
||||
syncDate: '동기화 시간',
|
||||
clean: '캐시 정리',
|
||||
|
||||
@@ -1125,6 +1125,13 @@ const message = {
|
||||
failedRecord: 'Rekod kegagalan',
|
||||
successRecord: 'Rekod berjaya',
|
||||
database: 'Pangkalan data sandaran',
|
||||
backupArgs: 'Argumen Sandaran',
|
||||
backupArgsHelper:
|
||||
'Argumen sandaran yang tidak disenaraikan boleh dimasukkan dan dipilih secara manual. Contoh: Masukkan --no-data dan pilih pilihan pertama dari senarai juntai bawah.',
|
||||
singleTransaction:
|
||||
'Sandaran jadual InnoDB menggunakan transaksi tunggal, sesuai untuk sandaran data isipadu besar',
|
||||
quick: 'Baca data baris demi baris daripada memuatkan keseluruhan jadual ke dalam ingatan, sesuai untuk sandaran data isipadu besar dan mesin ingatan rendah',
|
||||
skipLockTables: 'Sandaran tanpa mengunci semua jadual, sesuai untuk pangkalan data konkuren tinggi',
|
||||
missBackupAccount: 'Akaun sandaran tidak dijumpai',
|
||||
syncDate: 'Waktu penyelarasan',
|
||||
clean: 'Bersihkan cache',
|
||||
|
||||
@@ -1122,6 +1122,13 @@ const message = {
|
||||
failedRecord: 'Registros de falha',
|
||||
successRecord: 'Registros de sucesso',
|
||||
database: 'Backup de banco de dados',
|
||||
backupArgs: 'Argumentos de Backup',
|
||||
backupArgsHelper:
|
||||
'Argumentos de backup não listados podem ser inseridos e selecionados manualmente. Por exemplo: Digite --no-data e selecione a primeira opção da lista suspensa.',
|
||||
singleTransaction:
|
||||
'Faz backup de tabelas InnoDB usando uma única transação, adequado para backups de dados de grande volume',
|
||||
quick: 'Lê dados linha por linha em vez de carregar toda a tabela na memória, adequado para backups de dados de grande volume e máquinas com pouca memória',
|
||||
skipLockTables: 'Backup sem bloquear todas as tabelas, adequado para bancos de dados altamente concorrentes',
|
||||
missBackupAccount: 'A conta de backup não foi encontrada',
|
||||
syncDate: 'Data de sincronização',
|
||||
clean: 'Limpeza de cache',
|
||||
|
||||
@@ -1118,6 +1118,13 @@ const message = {
|
||||
failedRecord: 'Неудачные записи',
|
||||
successRecord: 'Успешные записи',
|
||||
database: 'Резервное копирование базы данных',
|
||||
backupArgs: 'Аргументы Резервного Копирования',
|
||||
backupArgsHelper:
|
||||
'Неперечисленные аргументы резервного копирования могут быть введены и выбраны вручную. Например: Введите --no-data и выберите первый вариант из выпадающего списка.',
|
||||
singleTransaction:
|
||||
'Резервное копирование таблиц InnoDB с использованием одной транзакции, подходит для резервного копирования данных большого объема',
|
||||
quick: 'Чтение данных построчно вместо загрузки всей таблицы в память, подходит для резервного копирования данных большого объема и машин с низкой памятью',
|
||||
skipLockTables: 'Резервное копирование без блокировки всех таблиц, подходит для высококонкурентных баз данных',
|
||||
missBackupAccount: 'Не удалось найти учетную запись резервного копирования',
|
||||
syncDate: 'Время синхронизации',
|
||||
clean: 'Очистка кэша',
|
||||
|
||||
@@ -1146,6 +1146,13 @@ const message = {
|
||||
failedRecord: 'Başarısız kayıtlar',
|
||||
successRecord: 'Başarılı kayıtlar',
|
||||
database: 'Veritabanını yedekle',
|
||||
backupArgs: 'Yedekleme Argümanları',
|
||||
backupArgsHelper:
|
||||
'Listelenmemiş yedekleme argümanları manuel olarak girilip seçilebilir. Örneğin: --no-data yazın ve açılır listeden ilk seçeneği seçin.',
|
||||
singleTransaction:
|
||||
'InnoDB tablolarını tek bir işlem kullanarak yedekler, büyük hacimli veri yedeklemeleri için uygundur',
|
||||
quick: 'Tüm tabloyu belleğe yüklemek yerine verileri satır satır okur, büyük hacimli veri ve düşük bellekli makine yedeklemeleri için uygundur',
|
||||
skipLockTables: 'Tüm tabloları kilitlemeden yedekleme, yüksek eşzamanlılığa sahip veritabanları için uygundur',
|
||||
missBackupAccount: 'Yedekleme hesabı bulunamadı',
|
||||
syncDate: 'Senkronizasyon zamanı ',
|
||||
clean: 'Önbellek temizleme',
|
||||
|
||||
@@ -1072,6 +1072,11 @@ const message = {
|
||||
rulesHelper: '支援多個排除規則,使用英文逗號 , 分隔,例如:*.log,*.sql',
|
||||
lastRecordTime: '上次執行情況',
|
||||
database: '備份資料庫',
|
||||
backupArgs: '備份參數',
|
||||
backupArgsHelper: '未列出的備份參數可手動輸入並選擇,例如:輸入 --no-data 後選擇下拉列表中的第一個選項',
|
||||
singleTransaction: '使用單一事務備份 InnoDB 表,適用於大數據量的備份',
|
||||
quick: '逐行讀取數據,而不是將整個表加載到內存中,適用於大數據量和低內存機器的備份',
|
||||
skipLockTables: '不鎖定所有表進行備份,適用於高併發的資料庫',
|
||||
missBackupAccount: '未能找到備份帳號',
|
||||
syncDate: '同步時間 ',
|
||||
clean: '快取清理',
|
||||
|
||||
@@ -1075,6 +1075,11 @@ const message = {
|
||||
rulesHelper: '支持多个排除规则,使用英文逗号 , 分隔,例如:*.log,*.sql',
|
||||
lastRecordTime: '上次执行情况',
|
||||
database: '备份数据库',
|
||||
backupArgs: '备份参数',
|
||||
backupArgsHelper: '未列出的备份参数可手动输入并选择,如: 输入 --no-data 后选择下拉列表中的第一个',
|
||||
singleTransaction: '使用单一事务备份 InnoDB 表,适用于大数据量的备份',
|
||||
quick: '逐行读取数据,而不是将整个表加载到内存中,适用于大数据量和低内存机器的备份',
|
||||
skipLockTables: '不锁定所有表进行备份,适用于高并发的数据库',
|
||||
missBackupAccount: '未能找到备份账号',
|
||||
syncDate: '同步时间 ',
|
||||
clean: '缓存清理',
|
||||
|
||||
@@ -21,6 +21,11 @@ export const weekOptions = [
|
||||
{ label: i18n.global.t('cronjob.saturday'), value: 6 },
|
||||
{ label: i18n.global.t('cronjob.sunday'), value: 0 },
|
||||
];
|
||||
export const mysqlArgs = [
|
||||
{ arg: '--single-transaction', description: i18n.global.t('cronjob.singleTransaction') },
|
||||
{ arg: '--quick', description: i18n.global.t('cronjob.quick') },
|
||||
{ arg: '--skip-lock-tables', description: i18n.global.t('cronjob.skipLockTables') },
|
||||
];
|
||||
function loadWeek(i: number) {
|
||||
for (const week of weekOptions) {
|
||||
if (week.value === i) {
|
||||
|
||||
@@ -335,6 +335,30 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</LayoutCol>
|
||||
<LayoutCol
|
||||
:span="20"
|
||||
v-if="
|
||||
form.type === 'database' &&
|
||||
(form.dbType === 'mysql' || form.dbType === 'mysql-cluster')
|
||||
"
|
||||
>
|
||||
<el-form-item :label="$t('cronjob.backupArgs')">
|
||||
<el-select v-model="form.argItems" filterable allow-create multiple>
|
||||
<el-option
|
||||
v-for="item in mysqlArgs"
|
||||
:key="item.arg"
|
||||
:value="item.arg"
|
||||
:label="item.arg"
|
||||
>
|
||||
{{ item.arg }}
|
||||
<span class="ml-2">{{ item.description }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span class="input-help">
|
||||
{{ $t('cronjob.backupArgsHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
</LayoutCol>
|
||||
<LayoutCol v-if="form.type === 'directory'">
|
||||
<el-form-item :label="$t('commons.button.backup')">
|
||||
<el-radio-group v-model="form.isDir" class="w-full">
|
||||
@@ -774,7 +798,6 @@ import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
||||
import InputTag from '@/components/input-tag/index.vue';
|
||||
import LayoutCol from '@/components/layout-col/form.vue';
|
||||
import CleanLogConfig from '@/views/cronjob/cronjob/config/clean-log.vue';
|
||||
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { listBackupOptions } from '@/api/modules/backup';
|
||||
@@ -797,6 +820,7 @@ import {
|
||||
transSpecToObj,
|
||||
weekOptions,
|
||||
cronjobTypes,
|
||||
mysqlArgs,
|
||||
} from '../helper';
|
||||
import { loadUsers } from '@/api/modules/toolbox';
|
||||
import { loadContainerUsers } from '@/api/modules/container';
|
||||
@@ -883,6 +907,8 @@ const form = reactive<Cronjob.CronjobInfo>({
|
||||
alertMethodItems: [],
|
||||
|
||||
scopes: [],
|
||||
args: '',
|
||||
argItems: [],
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
@@ -982,6 +1008,7 @@ const search = async () => {
|
||||
form.alertMethodItems = [];
|
||||
}
|
||||
form.scopes = res.data.scopes;
|
||||
form.argItems = res.data.args ? res.data.args.split(',') : [];
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
@@ -1481,6 +1508,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
form.url = form.urlItems.join(',');
|
||||
form.sourceAccountIDs = form.sourceAccountItems.join(',');
|
||||
form.spec = specs.join('&&');
|
||||
form.args = form.argItems.join(',');
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
|
||||
Reference in New Issue
Block a user