diff --git a/backend/app/dto/setting.go b/backend/app/dto/setting.go index bab7242ce..4a140473b 100644 --- a/backend/app/dto/setting.go +++ b/backend/app/dto/setting.go @@ -52,6 +52,8 @@ type SettingInfo struct { AppStoreSyncStatus string `json:"appStoreSyncStatus"` FileRecycleBin string `json:"fileRecycleBin"` + + SnapshotIgnore string `json:"snapshotIgnore"` } type SettingUpdate struct { diff --git a/backend/app/service/snapshot_create.go b/backend/app/service/snapshot_create.go index b0f2a8884..568c48f5d 100644 --- a/backend/app/service/snapshot_create.go +++ b/backend/app/service/snapshot_create.go @@ -138,7 +138,14 @@ func snapPanelData(snap snapHelper, localDir, targetDir string) { if strings.Contains(localDir, dataDir) { exclusionRules += ("." + strings.ReplaceAll(localDir, dataDir, "") + ";") } - + ignoreVal, _ := settingRepo.Get(settingRepo.WithByKey("SnapshotIgnore")) + rules := strings.Split(ignoreVal.Value, ",") + for _, ignore := range rules { + if len(ignore) == 0 || cmd.CheckIllegal(ignore) { + continue + } + exclusionRules += ("." + strings.ReplaceAll(ignore, dataDir, "") + ";") + } _ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": "OnSaveData"}) sysIP, _ := settingRepo.Get(settingRepo.WithByKey("SystemIP")) _ = settingRepo.Update("SystemIP", "") @@ -213,6 +220,7 @@ func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error { } } + exMap := make(map[string]struct{}) exStr := "" excludes := strings.Split(exclusionRules, ";") excludes = append(excludes, "*.sock") @@ -220,8 +228,12 @@ func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error { if len(exclude) == 0 { continue } + if _, ok := exMap[exclude]; ok { + continue + } exStr += " --exclude " exStr += exclude + exMap[exclude] = struct{}{} } commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir) diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index faae42bfb..dcad5937f 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -72,6 +72,8 @@ func Init() { migrations.UpdateSnapshotRecords, migrations.UpdateWebDavConf, + + migrations.AddSnapshotIgnore, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/v_1_10.go b/backend/init/migration/migrations/v_1_10.go new file mode 100644 index 000000000..f6897f006 --- /dev/null +++ b/backend/init/migration/migrations/v_1_10.go @@ -0,0 +1,17 @@ +package migrations + +import ( + "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +var AddSnapshotIgnore = &gormigrate.Migration{ + ID: "20240311-add-snapshot-ignore", + Migrate: func(tx *gorm.DB) error { + if err := tx.Create(&model.Setting{Key: "SnapshotIgnore", Value: "*.sock"}).Error; err != nil { + return err + } + return nil + }, +} diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts index c4c2c6de9..f64f9f62c 100644 --- a/frontend/src/api/interface/setting.ts +++ b/frontend/src/api/interface/setting.ts @@ -45,6 +45,7 @@ export namespace Setting { emailVars: string; weChatVars: string; dingVars: string; + snapshotIgnore: string; } export interface SettingUpdate { key: string; diff --git a/frontend/src/components/file-list/index.vue b/frontend/src/components/file-list/index.vue index 8baea171d..31fef7fe9 100644 --- a/frontend/src/components/file-list/index.vue +++ b/frontend/src/components/file-list/index.vue @@ -116,6 +116,10 @@ const props = defineProps({ type: Boolean, default: false, }, + isAll: { + type: Boolean, + default: false, + }, disabled: { type: Boolean, default: false, @@ -142,6 +146,9 @@ const closePage = () => { }; const disabledDir = (row: File.File) => { + if (props.isAll) { + return false; + } if (!props.dir) { return row.isDir; } diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index d97bfa4a6..27b3c646c 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1396,6 +1396,10 @@ const message = { snapshot: 'Snapshot', status: 'Snapshot status', + ignoreRule: 'Ignore Rule', + ignoreHelper: + 'This rule will be used to compress and backup the 1Panel data directory during snapshots, please modify with caution.', + ignoreHelper1: 'One item per line, e.g.: \n*.log\n/opt/1panel/cache', panelInfo: 'Write 1Panel basic information', panelBin: 'Backup 1Panel system files', daemonJson: 'Backup Docker configuration file', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index e8e291f36..a1384d660 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -1237,6 +1237,9 @@ const message = { snapshot: '快照', status: '快照狀態', + ignoreRule: '排除規則', + ignoreHelper: '快照時將使用該規則對 1Panel 數據目錄進行壓縮備份,請謹慎修改。', + ignoreHelper1: '一行一個,例: \n*.log\n/opt/1panel/cache', panelInfo: '寫入 1Panel 基礎信息', panelBin: '備份 1Panel 系統文件', daemonJson: '備份 Docker 配置文件', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 3b3238f31..36a9b3c27 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1237,6 +1237,9 @@ const message = { path: '路径', snapshot: '快照', + ignoreRule: '排除规则', + ignoreHelper: '快照时将使用该规则对 1Panel 数据目录进行压缩备份,请谨慎修改。', + ignoreHelper1: '一行一个,例: \n*.log\n/opt/1panel/cache', status: '快照状态', panelInfo: '写入 1Panel 基础信息', panelBin: '备份 1Panel 系统文件', diff --git a/frontend/src/views/setting/snapshot/ignore-rule/index.vue b/frontend/src/views/setting/snapshot/ignore-rule/index.vue new file mode 100644 index 000000000..9eff0eed6 --- /dev/null +++ b/frontend/src/views/setting/snapshot/ignore-rule/index.vue @@ -0,0 +1,153 @@ + + diff --git a/frontend/src/views/setting/snapshot/index.vue b/frontend/src/views/setting/snapshot/index.vue index 69129ee28..bc390e6ea 100644 --- a/frontend/src/views/setting/snapshot/index.vue +++ b/frontend/src/views/setting/snapshot/index.vue @@ -7,6 +7,9 @@ {{ $t('setting.createSnapshot') }} + + {{ $t('setting.ignoreRule') }} + {{ $t('setting.importSnapshot') }} @@ -163,6 +166,7 @@ + @@ -175,6 +179,7 @@ import { ElForm } from 'element-plus'; import { Rules } from '@/global/form-rules'; import i18n from '@/lang'; import { Setting } from '@/api/interface/setting'; +import IgnoreRule from '@/views/setting/snapshot/ignore-rule/index.vue'; import SnapStatus from '@/views/setting/snapshot/snap_status/index.vue'; import RecoverStatus from '@/views/setting/snapshot/status/index.vue'; import SnapshotImport from '@/views/setting/snapshot/import/index.vue'; @@ -193,6 +198,7 @@ const paginationConfig = reactive({ const searchName = ref(); const opRef = ref(); +const ignoreRef = ref(); const snapStatusRef = ref(); const recoverStatusRef = ref(); @@ -231,6 +237,10 @@ const onImport = () => { importRef.value.acceptParams({ names: names }); }; +const onIgnore = () => { + ignoreRef.value.acceptParams(); +}; + const handleClose = () => { drawerVisible.value = false; };