Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions agent/app/dto/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Expand Down
3 changes: 3 additions & 0 deletions agent/app/dto/cronjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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"`
}
Expand Down Expand Up @@ -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"`
Expand Down
1 change: 1 addition & 0 deletions agent/app/model/cronjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
10 changes: 8 additions & 2 deletions agent/app/service/backup_mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions agent/app/service/cronjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions agent/app/service/cronjob_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ type DatabaseHelper struct {
DBType string
Database string
Name string
Args []string
}

func addSkipTask(source string, taskItem *task.Task) {
Expand All @@ -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 {
Expand All @@ -410,6 +412,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
DBType: cronjob.DBType,
Database: pg.PostgresqlName,
Name: pg.Name,
Args: strings.Split(cronjob.Args, ","),
})
}
}
Expand All @@ -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)))
Expand All @@ -433,6 +437,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
DBType: cronjob.DBType,
Database: pgItem.PostgresqlName,
Name: pgItem.Name,
Args: strings.Split(cronjob.Args, ","),
})
}
}
Expand Down
1 change: 1 addition & 0 deletions agent/init/migration/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func InitAgentDB() {
migrations.AddisIPtoWebsiteSSL,
migrations.InitPingStatus,
migrations.UpdateApp,
migrations.AddCronjobArgs,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
Expand Down
7 changes: 7 additions & 0 deletions agent/init/migration/migrations/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{})
},
}
13 changes: 7 additions & 6 deletions agent/utils/mysql/client/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
12 changes: 10 additions & 2 deletions agent/utils/mysql/client/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions frontend/src/api/interface/cronjob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export namespace Cronjob {
alertMethodItems: Array<string>;

scopes: string[];
args: string;
argItems: Array<string>;
}
export interface Item {
val: string;
Expand Down Expand Up @@ -113,6 +115,7 @@ export namespace Cronjob {
alertMethod: string;

scopes?: string[];
args: string;
}
export interface CronjobTrans {
name: string;
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/components/backup/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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')"
Expand Down Expand Up @@ -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 () => {
Expand All @@ -178,6 +189,7 @@ const PushApp = defineAsyncComponent(async () => {
});

const selects = ref<any>([]);
const args = ref([]);
const loading = ref();
const opRef = ref();
const taskLogRef = ref();
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -352,6 +365,7 @@ const recover = async (row?: any) => {
const onBackup = async () => {
description.value = '';
secret.value = '';
args.value = [];
isBackup.value = true;
open.value = true;
};
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/lang/modules/es-es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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é',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lang/modules/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,13 @@ const message = {
failedRecord: '失敗記録',
successRecord: '成功した記録',
database: 'バックアップデータベース',
backupArgs: 'バックアップ引数',
backupArgsHelper:
'リストにないバックアップ引数は手動で入力して選択できます。例:--no-data を入力し、ドロップダウンリストの最初のオプションを選択してください。',
singleTransaction:
'単一トランザクションを使用して InnoDB テーブルをバックアップします。大容量データのバックアップに適しています',
quick: 'テーブル全体をメモリにロードする代わりに、データを行単位で読み取ります。大容量データや低メモリマシンのバックアップに適しています',
skipLockTables: 'すべてのテーブルをロックせずにバックアップします。高並列データベースに適しています',
missBackupAccount: 'バックアップアカウントは見つかりませんでした',
syncDate: '同期時間',
clean: 'キャッシュクリーン',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lang/modules/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,12 @@ const message = {
failedRecord: '실패한 레코드',
successRecord: '성공한 레코드',
database: '백업 데이터베이스',
backupArgs: '백업 인수',
backupArgsHelper:
'목록에 없는 백업 인수는 수동으로 입력하여 선택할 수 있습니다. 예: --no-data를 입력하고 드롭다운 목록의 첫 번째 옵션을 선택하세요.',
singleTransaction: '단일 트랜잭션을 사용하여 InnoDB 테이블을 백업하며, 대용량 데이터 백업에 적합합니다',
quick: '전체 테이블을 메모리에 로드하는 대신 데이터를 행별로 읽습니다. 대용량 데이터 및 저메모리 시스템 백업에 적합합니다',
skipLockTables: '모든 테이블을 잠그지 않고 백업합니다. 높은 동시성 데이터베이스에 적합합니다',
missBackupAccount: '백업 계정을 찾을 수 없습니다',
syncDate: '동기화 시간',
clean: '캐시 정리',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lang/modules/ms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lang/modules/pt-br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lang/modules/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,13 @@ const message = {
failedRecord: 'Неудачные записи',
successRecord: 'Успешные записи',
database: 'Резервное копирование базы данных',
backupArgs: 'Аргументы Резервного Копирования',
backupArgsHelper:
'Неперечисленные аргументы резервного копирования могут быть введены и выбраны вручную. Например: Введите --no-data и выберите первый вариант из выпадающего списка.',
singleTransaction:
'Резервное копирование таблиц InnoDB с использованием одной транзакции, подходит для резервного копирования данных большого объема',
quick: 'Чтение данных построчно вместо загрузки всей таблицы в память, подходит для резервного копирования данных большого объема и машин с низкой памятью',
skipLockTables: 'Резервное копирование без блокировки всех таблиц, подходит для высококонкурентных баз данных',
missBackupAccount: 'Не удалось найти учетную запись резервного копирования',
syncDate: 'Время синхронизации',
clean: 'Очистка кэша',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lang/modules/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Loading
Loading