From 958e6d805ac51fd40381865551b6f655166e727f Mon Sep 17 00:00:00 2001 From: woblerr Date: Sat, 28 Sep 2024 00:14:54 +0300 Subject: [PATCH 1/9] Refactor backup delete process. gpbackup save information in $MASTER_DATA_DIRECTORY/backups. When deleting a backup using a plugin, it is necessary to clear local backup information on the master. Added deletion of files on the master when deleting a backup using a plugin. Also, performed a small refactoring with the addition of handlers for error handling. There may be cases when a backup hangs in the "In Progress" status. Additionally, backups in the "Failure" status save information about themselves. You can get a report for them, and they also need to be deleted. The conditions in the checkBackupCanBeUsed() function have been changed. The conditions in checkBackupCanBeUsed() function have been changed to work with backups that have not been deleted. This allows for the deletion of backups in "Failure" or "In Progress" statuses. --- cmd/backup_delete.go | 125 ++++++++++++++++++++--------------------- cmd/wrappers.go | 38 ++++++++----- cmd/wrappers_test.go | 8 +-- gpbckpconfig/struct.go | 13 +++-- textmsg/info.go | 6 +- textmsg/info_test.go | 33 ++++++++--- 6 files changed, 126 insertions(+), 97 deletions(-) diff --git a/cmd/backup_delete.go b/cmd/backup_delete.go index d02aefb..519188e 100644 --- a/cmd/backup_delete.go +++ b/cmd/backup_delete.go @@ -360,16 +360,35 @@ func backupDeleteDBPluginFunc(backupName, pluginConfigPath string, pluginConfig gplog.Error(stderr) } if errdel != nil { - gplog.Error(textmsg.ErrorTextUnableDeleteBackup(backupName, errdel)) - err = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedPluginFailed, hDB) - if err != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedPluginFailed, backupName, err)) - } + handleErrorDB(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, errdel), gpbckpconfig.DateDeletedPluginFailed, hDB) if !ignoreErrors { return errdel } } gplog.Info(stdout) + backupData, err := gpbckpconfig.GetBackupDataDB(backupName, hDB) + if err != nil { + handleErrorDB(backupName, textmsg.ErrorTextUnableGetBackupInfo(backupName, err), gpbckpconfig.DateDeletedPluginFailed, hDB) + if !ignoreErrors { + return err + } + } + bckpDir, _, _, err := getBackupMasterDir("", backupData.BackupDir, backupData.DatabaseName) + if err != nil { + handleErrorDB(backupName, textmsg.ErrorTextUnableGetBackupPath("backup directory", backupName, err), gpbckpconfig.DateDeletedPluginFailed, hDB) + if !ignoreErrors { + return err + } + } + gplog.Debug(textmsg.InfoTextCommandExecution("delete directory", gpbckpconfig.BackupDirPath(bckpDir, backupName))) + // Delete local files on master. + err = os.RemoveAll(gpbckpconfig.BackupDirPath(bckpDir, backupName)) + if err != nil { + handleErrorDB(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, err), gpbckpconfig.DateDeletedPluginFailed, hDB) + if !ignoreErrors { + return err + } + } err = gpbckpconfig.UpdateDeleteStatus(backupName, dateDeleted, hDB) if err != nil { gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(dateDeleted, backupName, err)) @@ -390,31 +409,19 @@ func backupDeleteDBLocalFunc(backupName, backupDir string, maxParallelProcesses } backupData, err := gpbckpconfig.GetBackupDataDB(backupName, hDB) if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupInfo(backupName, err)) - errUpdate = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedLocalFailed, hDB) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, err)) - } + handleErrorDB(backupName, textmsg.ErrorTextUnableGetBackupInfo(backupName, err), gpbckpconfig.DateDeletedLocalFailed, hDB) return err } bckpDir, segPrefix, isSingleBackupDir, err := getBackupMasterDir(backupDir, backupData.BackupDir, backupData.DatabaseName) if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupPath("backup directory", backupName, err)) - errUpdate = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedLocalFailed, hDB) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) - } + handleErrorDB(backupName, textmsg.ErrorTextUnableGetBackupPath("backup directory", backupName, err), gpbckpconfig.DateDeletedLocalFailed, hDB) return err } gplog.Debug(textmsg.InfoTextBackupDirPath(bckpDir)) gplog.Debug(textmsg.InfoTextSegmentPrefix(segPrefix)) backupType, err := backupData.GetBackupType() if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupValue("type", backupData.Timestamp, err)) - errUpdate = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedLocalFailed, hDB) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) - } + handleErrorDB(backupName, textmsg.ErrorTextUnableGetBackupValue("type", backupName, err), gpbckpconfig.DateDeletedLocalFailed, hDB) return err } // If backup type is not "metadata-only", we should delete files on segments and master. @@ -423,33 +430,25 @@ func backupDeleteDBLocalFunc(backupName, backupDir string, maxParallelProcesses var errSeg error segConfig, errSeg := getSegmentConfigurationClusterInfo(backupData.DatabaseName) if errSeg != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupPath("segment configuration", backupName, errSeg)) - errUpdate = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedLocalFailed, hDB) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) + handleErrorDB(backupName, textmsg.ErrorTextUnableGetBackupPath("segment configuration", backupName, errSeg), gpbckpconfig.DateDeletedLocalFailed, hDB) + if !ignoreErrors { + return errSeg } - return errSeg } // Execute on segments. errSeg = executeDeleteBackupOnSegments(backupDir, backupData.BackupDir, backupName, segPrefix, isSingleBackupDir, ignoreErrors, segConfig, maxParallelProcesses) if errSeg != nil { - gplog.Error(textmsg.ErrorTextUnableDeleteBackup(backupName, errSeg)) - errUpdate = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedLocalFailed, hDB) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) + handleErrorDB(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, errSeg), gpbckpconfig.DateDeletedLocalFailed, hDB) + if !ignoreErrors { + return errSeg } - return errSeg } } // Delete files on master. gplog.Debug(textmsg.InfoTextCommandExecution("delete directory", gpbckpconfig.BackupDirPath(bckpDir, backupName))) err = os.RemoveAll(gpbckpconfig.BackupDirPath(bckpDir, backupName)) if err != nil { - gplog.Error(textmsg.ErrorTextUnableDeleteBackup(backupName, err)) - errUpdate = gpbckpconfig.UpdateDeleteStatus(backupName, gpbckpconfig.DateDeletedLocalFailed, hDB) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) - } + handleErrorDB(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, err), gpbckpconfig.DateDeletedLocalFailed, hDB) if !ignoreErrors { return err } @@ -556,16 +555,28 @@ func backupDeleteFilePluginFunc(backupData gpbckpconfig.BackupConfig, parseHData gplog.Error(stderr) } if errdel != nil { - gplog.Error(textmsg.ErrorTextUnableDeleteBackup(backupName, errdel)) - errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, gpbckpconfig.DateDeletedPluginFailed) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedPluginFailed, backupName, errUpdate)) - } + handleErrorFile(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, errdel), gpbckpconfig.DateDeletedPluginFailed, parseHData) if !ignoreErrors { return errdel } } gplog.Info(stdout) + // Delete local files on master. + bckpDir, _, _, err := getBackupMasterDir("", backupData.BackupDir, backupData.DatabaseName) + if err != nil { + handleErrorFile(backupName, textmsg.ErrorTextUnableGetBackupPath("backup directory", backupName, err), gpbckpconfig.DateDeletedPluginFailed, parseHData) + if !ignoreErrors { + return err + } + } + gplog.Debug(textmsg.InfoTextCommandExecution("delete directory", gpbckpconfig.BackupDirPath(bckpDir, backupName))) + err = os.RemoveAll(gpbckpconfig.BackupDirPath(bckpDir, backupName)) + if err != nil { + handleErrorFile(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, err), gpbckpconfig.DateDeletedPluginFailed, parseHData) + if !ignoreErrors { + return err + } + } errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, dateDeleted) if errUpdate != nil { gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(dateDeleted, backupName, errUpdate)) @@ -587,22 +598,14 @@ func backupDeleteFileLocalFunc(backupData gpbckpconfig.BackupConfig, parseHData } bckpDir, segPrefix, isSingleBackupDir, err := getBackupMasterDir(backupDir, backupData.BackupDir, backupData.DatabaseName) if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupPath("backup directory", backupName, err)) - errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, gpbckpconfig.DateDeletedLocalFailed) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) - } + handleErrorFile(backupName, textmsg.ErrorTextUnableGetBackupPath("backup directory", backupName, err), gpbckpconfig.DateDeletedLocalFailed, parseHData) return err } gplog.Debug(textmsg.InfoTextBackupDirPath(bckpDir)) gplog.Debug(textmsg.InfoTextSegmentPrefix(segPrefix)) backupType, err := backupData.GetBackupType() if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupValue("type", backupData.Timestamp, err)) - errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, gpbckpconfig.DateDeletedLocalFailed) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) - } + handleErrorFile(backupName, textmsg.ErrorTextUnableGetBackupValue("type", backupName, err), gpbckpconfig.DateDeletedLocalFailed, parseHData) return err } // If backup type is not "metadata-only", we should delete files on segments and master. @@ -611,33 +614,25 @@ func backupDeleteFileLocalFunc(backupData gpbckpconfig.BackupConfig, parseHData var errSeg error segConfig, errSeg := getSegmentConfigurationClusterInfo(backupData.DatabaseName) if errSeg != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupPath("segment configuration", backupName, errSeg)) - errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, gpbckpconfig.DateDeletedLocalFailed) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) + handleErrorFile(backupName, textmsg.ErrorTextUnableGetBackupPath("segment configuration", backupName, errSeg), gpbckpconfig.DateDeletedLocalFailed, parseHData) + if !ignoreErrors { + return errSeg } - return errSeg } // Execute on segments. errSeg = executeDeleteBackupOnSegments(backupDir, backupData.BackupDir, backupName, segPrefix, isSingleBackupDir, ignoreErrors, segConfig, maxParallelProcesses) if errSeg != nil { - gplog.Error(textmsg.ErrorTextUnableDeleteBackup(backupName, errSeg)) - errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, gpbckpconfig.DateDeletedLocalFailed) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) + handleErrorFile(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, errSeg), gpbckpconfig.DateDeletedLocalFailed, parseHData) + if !ignoreErrors { + return errSeg } - return errSeg } } // Delete files on master. gplog.Debug(textmsg.InfoTextCommandExecution("delete directory", gpbckpconfig.BackupDirPath(bckpDir, backupName))) err = os.RemoveAll(gpbckpconfig.BackupDirPath(bckpDir, backupName)) if err != nil { - gplog.Error(textmsg.ErrorTextUnableDeleteBackup(backupName, err)) - errUpdate = parseHData.UpdateBackupConfigDateDeleted(backupName, gpbckpconfig.DateDeletedLocalFailed) - if errUpdate != nil { - gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(gpbckpconfig.DateDeletedLocalFailed, backupName, errUpdate)) - } + handleErrorFile(backupName, textmsg.ErrorTextUnableDeleteBackup(backupName, err), gpbckpconfig.DateDeletedLocalFailed, parseHData) if !ignoreErrors { return err } diff --git a/cmd/wrappers.go b/cmd/wrappers.go index 07c9aed..c3b24b7 100644 --- a/cmd/wrappers.go +++ b/cmd/wrappers.go @@ -1,6 +1,7 @@ package cmd import ( + "database/sql" "fmt" "os" "path/filepath" @@ -127,31 +128,24 @@ func formatBackupDuration(value float64) string { return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) } -// The backup can be used in one of the cases: -// - backup has success status and backup is active -// - backup has success status, not active, but the --force flag is set. +// The backup can be used in one of the cases for local and plugin backups: +// - backup is active +// - backup is not active, but the --force flag is set. // Returns: // - true, if backup can be used; // - false, if backup can't be used. // Errors and warnings will also returned and logged. func checkBackupCanBeUsed(deleteForce, skipLocalBackup bool, backupData gpbckpconfig.BackupConfig) (bool, error) { result := false - backupSuccessStatus, err := backupData.IsSuccess() + err := checkLocalBackupStatus(skipLocalBackup, backupData.IsLocal()) if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupValue("status", backupData.Timestamp, err)) - // There is no point in performing further checks. + gplog.Error(textmsg.ErrorTextUnableWorkBackup(backupData.Timestamp, err)) return result, err } - if !backupSuccessStatus { - gplog.Warn(textmsg.InfoTextBackupFailedStatus(backupData.Timestamp)) + if backupData.IsInProgress() && !deleteForce { + gplog.Error(textmsg.InfoTextBackupStatus(backupData.Timestamp, backupData.Status)) return result, nil } - err = checkLocalBackupStatus(skipLocalBackup, backupData.IsLocal()) - if err != nil { - gplog.Error(textmsg.ErrorTextUnableWorkBackup(backupData.Timestamp, err)) - return result, err - - } backupDateDeleted, errDateDeleted := backupData.GetBackupDateDeleted() if errDateDeleted != nil { gplog.Error(textmsg.ErrorTextUnableGetBackupValue("date deletion", backupData.Timestamp, errDateDeleted)) @@ -273,3 +267,19 @@ func getSegmentConfigurationClusterInfo(dbName string) ([]gpbckpconfig.SegmentCo } return queryResult, nil } + +func handleErrorDB(backupName, errorMessage, backupStatus string, hDB *sql.DB) { + gplog.Error(errorMessage) + err := gpbckpconfig.UpdateDeleteStatus(backupName, backupStatus, hDB) + if err != nil { + gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(backupStatus, backupName, err)) + } +} + +func handleErrorFile(backupName, errorMessage, backupStatus string, parseHData *gpbckpconfig.History) { + gplog.Error(errorMessage) + err := parseHData.UpdateBackupConfigDateDeleted(backupName, backupStatus) + if err != nil { + gplog.Error(textmsg.ErrorTextUnableSetBackupStatus(backupStatus, backupName, err)) + } +} diff --git a/cmd/wrappers_test.go b/cmd/wrappers_test.go index da3c519..c71666f 100644 --- a/cmd/wrappers_test.go +++ b/cmd/wrappers_test.go @@ -211,7 +211,7 @@ func TestCheckBackupCanBeUsed(t *testing.T) { Plugin: gpbckpconfig.BackupS3Plugin, DateDeleted: "", }, - want: false, + want: true, wantErr: false, }, { @@ -223,7 +223,7 @@ func TestCheckBackupCanBeUsed(t *testing.T) { Plugin: gpbckpconfig.BackupS3Plugin, DateDeleted: "", }, - want: false, + want: true, wantErr: false, }, { @@ -283,8 +283,8 @@ func TestCheckBackupCanBeUsed(t *testing.T) { Plugin: gpbckpconfig.BackupS3Plugin, DateDeleted: "", }, - want: false, - wantErr: true, + want: true, + wantErr: false, }, { name: "Successful backup with plugin with deletion in progress and force", diff --git a/gpbckpconfig/struct.go b/gpbckpconfig/struct.go index bc344c2..4924b74 100644 --- a/gpbckpconfig/struct.go +++ b/gpbckpconfig/struct.go @@ -59,8 +59,9 @@ const ( BackupTypeDataOnly = "data-only" BackupTypeMetadataOnly = "metadata-only" // Backup statuses. - BackupStatusSuccess = "Success" - BackupStatusFailure = "Failure" + BackupStatusSuccess = "Success" + BackupStatusFailure = "Failure" + BackupStatusInProgress = "In Progress" // Object filtering types. objectFilteringIncludeSchema = "include-schema" objectFilteringExcludeSchema = "exclude-schema" @@ -200,14 +201,14 @@ func (backupConfig BackupConfig) GetBackupDateDeleted() (string, error) { // IsSuccess Check backup status. // Returns: // - true - if backup is successful, -// - false - false if backup is not successful. +// - false - false if backup is not successful or in progress. // // In all other cases, an error is returned. func (backupConfig BackupConfig) IsSuccess() (bool, error) { switch backupConfig.Status { case BackupStatusSuccess: return true, nil - case BackupStatusFailure: + case BackupStatusFailure, BackupStatusInProgress: return false, nil default: return false, errors.New("backup status does not match any of the available values") @@ -222,6 +223,10 @@ func (backupConfig BackupConfig) IsLocal() bool { return backupConfig.Plugin == "" } +func (backupConfig BackupConfig) IsInProgress() bool { + return backupConfig.Status == BackupStatusInProgress +} + // GetReportFilePathPlugin Return path to report file name for specific plugin. // If custom report path is set, it is returned. // Otherwise, the path from plugin is returned. diff --git a/textmsg/info.go b/textmsg/info.go index dc98cda..8ab403a 100644 --- a/textmsg/info.go +++ b/textmsg/info.go @@ -10,11 +10,11 @@ func InfoTextBackupDeleteStart(backupName string) string { } func InfoTextBackupAlreadyDeleted(backupName string) string { - return fmt.Sprintf("Backup %s has already been deleted.", backupName) + return fmt.Sprintf("Backup %s has already been deleted", backupName) } -func InfoTextBackupFailedStatus(backupName string) string { - return fmt.Sprintf("Backup %s has failed status.", backupName) +func InfoTextBackupStatus(backupName, backupStatus string) string { + return fmt.Sprintf("Backup %s has status: %s", backupName, backupStatus) } func InfoTextBackupDeleteSuccess(backupName string) string { diff --git a/textmsg/info_test.go b/textmsg/info_test.go index c6261fa..6e385b8 100644 --- a/textmsg/info_test.go +++ b/textmsg/info_test.go @@ -25,13 +25,7 @@ func TestInfoTextFunctionAndArg(t *testing.T) { name: "Test InfoTextBackupAlreadyDeleted", value: "TestBackup", function: InfoTextBackupAlreadyDeleted, - want: "Backup TestBackup has already been deleted.", - }, - { - name: "Test InfoTextBackupUnableDeleteFailed", - value: "TestBackup", - function: InfoTextBackupFailedStatus, - want: "Backup TestBackup has failed status.", + want: "Backup TestBackup has already been deleted", }, { name: "Test InfoTextBackupDirPath", @@ -55,6 +49,31 @@ func TestInfoTextFunctionAndArg(t *testing.T) { } } +func TestInfoTextFunctionAndTwoArgs(t *testing.T) { + tests := []struct { + name string + value1 string + value2 string + function func(string, string) string + want string + }{ + { + name: "Test InfoTextBackupUnableDeleteFailed", + value1: "TestBackup", + value2: "In Progress", + function: InfoTextBackupStatus, + want: "Backup TestBackup has status: In Progress", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.function(tt.value1, tt.value2); got != tt.want { + t.Errorf("\nVariables do not match:\n%s\nwant:\n%s", got, tt.want) + } + }) + } +} + func TestInfoTextFunctionAndMultipleArgs(t *testing.T) { tests := []struct { name string From 5e3673873d86485c1c7acbec28a0e1850b25bb6e Mon Sep 17 00:00:00 2001 From: woblerr Date: Sat, 28 Sep 2024 00:20:37 +0300 Subject: [PATCH 2/9] Refactoring history-clean command. Remove --deleted flag. Only deleted backups are deleted. In order to delete information about backup from the database, it must have the deleted status. --- cmd/{history-clean.go => history_clean.go} | 39 +++-------- gpbckpconfig/utils_db.go | 80 ++++++++++------------ gpbckpconfig/utils_db_test.go | 22 +++--- 3 files changed, 58 insertions(+), 83 deletions(-) rename cmd/{history-clean.go => history_clean.go} (78%) diff --git a/cmd/history-clean.go b/cmd/history_clean.go similarity index 78% rename from cmd/history-clean.go rename to cmd/history_clean.go index ed135ed..41db7a0 100644 --- a/cmd/history-clean.go +++ b/cmd/history_clean.go @@ -14,7 +14,6 @@ import ( var ( historyCleanBeforeTimestamp string historyCleanOlderThenDays uint - historyCleanDeleted bool ) var historyCleanCmd = &cobra.Command{ @@ -23,9 +22,7 @@ var historyCleanCmd = &cobra.Command{ Long: `Clean failed and deleted backups from the history database. Only the database is being cleaned up. -By default, information is deleted only about failed backups from gpbackup_history.db. - -To delete information about deleted backups, use the --deleted option. +Information is deleted only about deleted backups from gpbackup_history.db. Each backup must be deleted first. To delete information about backups older than the given timestamp, use the --before-timestamp option. To delete information about backups older than the given number of days, use the --older-than-day option. @@ -63,12 +60,6 @@ func init() { "", "delete information about backups older than the given timestamp", ) - historyCleanCmd.Flags().BoolVar( - &historyCleanDeleted, - deletedFlagName, - false, - "delete information about deleted backups", - ) historyCleanCmd.MarkFlagsMutuallyExclusive(beforeTimestampFlagName, olderThenDaysFlagName) } @@ -114,7 +105,7 @@ func cleanHistory() error { gplog.Error(textmsg.ErrorTextUnableActionHistoryDB("close", closeErr)) } }() - err = historyCleanDB(beforeTimestamp, historyCleanDeleted, hDB) + err = historyCleanDB(beforeTimestamp, hDB) if err != nil { return err } @@ -126,7 +117,7 @@ func cleanHistory() error { return err } if len(parseHData.BackupConfigs) != 0 { - err = historyCleanFile(beforeTimestamp, historyCleanDeleted, &parseHData) + err = historyCleanFile(beforeTimestamp, &parseHData) if err != nil { return err } @@ -141,15 +132,15 @@ func cleanHistory() error { return nil } -func historyCleanDB(cutOffTimestamp string, cleanDeleted bool, hDB *sql.DB) error { - backupList, err := gpbckpconfig.GetBackupNamesForCleanBeforeTimestamp(cutOffTimestamp, cleanDeleted, hDB) +func historyCleanDB(cutOffTimestamp string, hDB *sql.DB) error { + backupList, err := gpbckpconfig.GetBackupNamesForCleanBeforeTimestamp(cutOffTimestamp, hDB) if err != nil { gplog.Error(textmsg.ErrorTextUnableReadHistoryDB(err)) return err } if len(backupList) > 0 { gplog.Debug(textmsg.InfoTextBackupDeleteListFromHistory(backupList)) - err := gpbckpconfig.CleanBackupsDB(backupList, sqliteDeleteBatchSize, cleanDeleted, hDB) + err := gpbckpconfig.CleanBackupsDB(backupList, sqliteDeleteBatchSize, hDB) if err != nil { return err } @@ -159,30 +150,20 @@ func historyCleanDB(cutOffTimestamp string, cleanDeleted bool, hDB *sql.DB) erro return nil } -func historyCleanFile(cutOffTimestamp string, cleanDeleted bool, parseHData *gpbckpconfig.History) error { +func historyCleanFile(cutOffTimestamp string, parseHData *gpbckpconfig.History) error { backupIdxs := make([]int, 0) backupList := make([]string, 0) for idx, backupConfig := range parseHData.BackupConfigs { // In history file we have sorted timestamps by descending order. if backupConfig.Timestamp < cutOffTimestamp { - backupSuccessStatus, err := backupConfig.IsSuccess() + backupDateDeleted, err := backupConfig.GetBackupDateDeleted() if err != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupValue("status", backupConfig.Timestamp, err)) + gplog.Error(textmsg.ErrorTextUnableGetBackupValue("date deletion", backupConfig.Timestamp, err)) return err } - if !backupSuccessStatus { + if !gpbckpconfig.IsBackupActive(backupDateDeleted) && (backupDateDeleted != gpbckpconfig.DateDeletedInProgress) { backupIdxs = append(backupIdxs, idx) backupList = append(backupList, backupConfig.Timestamp) - } else if cleanDeleted { - backupDateDeleted, errDateDeleted := backupConfig.GetBackupDateDeleted() - if errDateDeleted != nil { - gplog.Error(textmsg.ErrorTextUnableGetBackupValue("date deletion", backupConfig.Timestamp, errDateDeleted)) - return err - } - if !gpbckpconfig.IsBackupActive(backupDateDeleted) && (backupDateDeleted != gpbckpconfig.DateDeletedInProgress) { - backupIdxs = append(backupIdxs, idx) - backupList = append(backupList, backupConfig.Timestamp) - } } } } diff --git a/gpbckpconfig/utils_db.go b/gpbckpconfig/utils_db.go index 0687e47..be16eb1 100644 --- a/gpbckpconfig/utils_db.go +++ b/gpbckpconfig/utils_db.go @@ -39,8 +39,8 @@ func GetBackupNamesBeforeTimestamp(timestamp string, historyDB *sql.DB) ([]strin return execQueryFunc(getBackupNameBeforeTimestampQuery(timestamp), historyDB) } -func GetBackupNamesForCleanBeforeTimestamp(timestamp string, cleanD bool, historyDB *sql.DB) ([]string, error) { - return execQueryFunc(getBackupNameForCleanBeforeTimestampQuery(timestamp, cleanD), historyDB) +func GetBackupNamesForCleanBeforeTimestamp(timestamp string, historyDB *sql.DB) ([]string, error) { + return execQueryFunc(getBackupNameForCleanBeforeTimestampQuery(timestamp), historyDB) } func getBackupNameQuery(showD, showF bool) string { @@ -73,7 +73,7 @@ ORDER BY timestamp DESC; `, backupName, backupName) } -// Only active backups, "In progress", deleted and failed statuses - hidden. +// Only active backups, "In progress", deleted and failed statuses - hidden. func getBackupNameBeforeTimestampQuery(timestamp string) string { return fmt.Sprintf(` SELECT timestamp @@ -82,21 +82,19 @@ WHERE timestamp < '%s' AND status != '%s' AND date_deleted IN ('', '%s', '%s') ORDER BY timestamp DESC; -`, timestamp, BackupStatusFailure, DateDeletedPluginFailed, DateDeletedLocalFailed) +`, timestamp, BackupStatusInProgress, DateDeletedPluginFailed, DateDeletedLocalFailed) } -func getBackupNameForCleanBeforeTimestampQuery(timestamp string, cleanD bool) string { - orderBy := "ORDER BY timestamp DESC;" - getBackupsQuery := fmt.Sprintf("SELECT timestamp FROM backups WHERE timestamp < '%s'", timestamp) - switch { - case cleanD: - // Return deleted, failed backup. - getBackupsQuery = fmt.Sprintf("%s AND (status = '%s' OR date_deleted NOT IN ('', '%s', '%s', '%s')) %s", getBackupsQuery, BackupStatusFailure, DateDeletedPluginFailed, DateDeletedLocalFailed, DateDeletedInProgress, orderBy) - default: - // Return failed backups. - getBackupsQuery = fmt.Sprintf("%s AND status = '%s' %s", getBackupsQuery, BackupStatusFailure, orderBy) - } - return getBackupsQuery +// Only deleted backups. +func getBackupNameForCleanBeforeTimestampQuery(timestamp string) string { + return fmt.Sprintf(` +SELECT timestamp +FROM backups +WHERE timestamp < '%s' + AND date_deleted NOT IN ('', '%s', '%s', '%s') +ORDER BY timestamp DESC; +`, timestamp, DateDeletedPluginFailed, DateDeletedLocalFailed, DateDeletedInProgress) + } // UpdateDeleteStatus Updates the date_deleted column in the history database. @@ -109,7 +107,7 @@ func UpdateDeleteStatus(backupName, dateDeleted string, historyDB *sql.DB) error } // CleanBackupsDB cleans the backup history database by deleting backups based on the given list of backup names. -func CleanBackupsDB(list []string, batchSize int, cleanD bool, historyDB *sql.DB) error { +func CleanBackupsDB(list []string, batchSize int, historyDB *sql.DB) error { for i := 0; i < len(list); i += batchSize { end := i + batchSize if end > len(list) { @@ -121,31 +119,29 @@ func CleanBackupsDB(list []string, batchSize int, cleanD bool, historyDB *sql.DB if err != nil { return err } - if cleanD { - err = execStatementFunc(deleteBackupsFormTableQuery("restore_plans", idStr), historyDB) - if err != nil { - return err - } - err = execStatementFunc(deleteBackupsFormTableQuery("restore_plan_tables", idStr), historyDB) - if err != nil { - return err - } - err = execStatementFunc(deleteBackupsFormTableQuery("exclude_relations", idStr), historyDB) - if err != nil { - return err - } - err = execStatementFunc(deleteBackupsFormTableQuery("exclude_schemas", idStr), historyDB) - if err != nil { - return err - } - err = execStatementFunc(deleteBackupsFormTableQuery("include_relations", idStr), historyDB) - if err != nil { - return err - } - err = execStatementFunc(deleteBackupsFormTableQuery("include_schemas", idStr), historyDB) - if err != nil { - return err - } + err = execStatementFunc(deleteBackupsFormTableQuery("restore_plans", idStr), historyDB) + if err != nil { + return err + } + err = execStatementFunc(deleteBackupsFormTableQuery("restore_plan_tables", idStr), historyDB) + if err != nil { + return err + } + err = execStatementFunc(deleteBackupsFormTableQuery("exclude_relations", idStr), historyDB) + if err != nil { + return err + } + err = execStatementFunc(deleteBackupsFormTableQuery("exclude_schemas", idStr), historyDB) + if err != nil { + return err + } + err = execStatementFunc(deleteBackupsFormTableQuery("include_relations", idStr), historyDB) + if err != nil { + return err + } + err = execStatementFunc(deleteBackupsFormTableQuery("include_schemas", idStr), historyDB) + if err != nil { + return err } } return nil diff --git a/gpbckpconfig/utils_db_test.go b/gpbckpconfig/utils_db_test.go index 901b342..f0abaa9 100644 --- a/gpbckpconfig/utils_db_test.go +++ b/gpbckpconfig/utils_db_test.go @@ -69,7 +69,7 @@ ORDER BY timestamp DESC; SELECT timestamp FROM backups WHERE timestamp < '20240101120000' - AND status != 'Failure' + AND status != 'In Progress' AND date_deleted IN ('', 'Plugin Backup Delete Failed', 'Local Delete Failed') ORDER BY timestamp DESC; `}, @@ -91,22 +91,20 @@ func TestGetBackupNameForCleanBeforeTimestampQuery(t *testing.T) { want string }{ { - name: "Show deleted and failed backups", + name: "Show backups", value: "20240101120000", showD: true, - want: `SELECT timestamp FROM backups WHERE timestamp < '20240101120000' AND (status = 'Failure' OR date_deleted NOT IN ('', 'Plugin Backup Delete Failed', 'Local Delete Failed', 'In progress')) ORDER BY timestamp DESC;`, - }, - { - name: "Show only failed backups", - value: "20240101120000", - showD: false, - want: `SELECT timestamp FROM backups WHERE timestamp < '20240101120000' AND status = 'Failure' ORDER BY timestamp DESC;`, - }, + want: ` +SELECT timestamp +FROM backups +WHERE timestamp < '20240101120000' + AND date_deleted NOT IN ('', 'Plugin Backup Delete Failed', 'Local Delete Failed', 'In progress') +ORDER BY timestamp DESC; +`}, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := getBackupNameForCleanBeforeTimestampQuery(tt.value, tt.showD); got != tt.want { + if got := getBackupNameForCleanBeforeTimestampQuery(tt.value); got != tt.want { t.Errorf("getBackupNameForCleanBeforeTimestampQuery(%v, %v):\n%v\nwant:\n%v", tt.value, tt.showD, got, tt.want) } }) From 2c138ee9f8ee055471299297c4e805bda47ab4c6 Mon Sep 17 00:00:00 2001 From: woblerr Date: Tue, 1 Oct 2024 23:55:06 +0300 Subject: [PATCH 3/9] Remove outdated e2e tests. E2e tests tests will be refactored in the future. --- e2e_tests/scripts/run_backup-clean.sh | 43 ------------------ e2e_tests/scripts/run_backup-delete.sh | 61 +++----------------------- 2 files changed, 7 insertions(+), 97 deletions(-) diff --git a/e2e_tests/scripts/run_backup-clean.sh b/e2e_tests/scripts/run_backup-clean.sh index 4d3988c..cd103af 100755 --- a/e2e_tests/scripts/run_backup-clean.sh +++ b/e2e_tests/scripts/run_backup-clean.sh @@ -53,49 +53,6 @@ if [ "${result_cnt_sqlite}" != "${TEST_CNT_SQL}" ]; then fi echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} passed." -################################################################ -# Test 2. -# Test cascade delete option. -# All backupd older than timestamp should be deleted. -TEST_ID="2" - -gpbackman ${GPBACKMAN_TEST_COMMAND} \ ---history-file ${WORK_DIR}/gpbackup_history_incremental_plugin.yaml \ ---before-timestamp ${TIMESTAMP} \ ---plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml \ ---cascade - -gpbackman ${GPBACKMAN_TEST_COMMAND} \ ---history-db ${WORK_DIR}/gpbackup_history.db \ ---before-timestamp ${TIMESTAMP} \ ---plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml \ ---cascade - -GPBACKMAN_RESULT_YAML=$(gpbackman backup-info \ ---history-file ${WORK_DIR}/gpbackup_history_incremental_plugin.yaml \ ---deleted) - -GPBACKMAN_RESULT_SQLITE=$(gpbackman backup-info \ ---history-db ${WORK_DIR}/gpbackup_history.db \ ---deleted) - -# After successful delete, in history there should be 11 fo sql and 7 for yaml backup with date deleted info. -TEST_CNT_YAML=7 -TEST_CNT_SQL=17 - -echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID}." -result_cnt_yaml=$(echo "${GPBACKMAN_RESULT_YAML}" | cut -f9 -d'|' | awk '{$1=$1};1' | grep -E ${DATE_REGEX} | wc -l) -if [ "${result_cnt_yaml}" != "${TEST_CNT_YAML}" ]; then - echo -e "[ERROR] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} failed.\nget_yaml=${result_cnt_yaml}, want=${TEST_CNT_YAML}" - exit 1 -fi - -result_cnt_sqlite=$(echo "${GPBACKMAN_RESULT_SQLITE}" | cut -f9 -d'|' | awk '{$1=$1};1' | grep -E ${DATE_REGEX} | wc -l) -if [ "${result_cnt_sqlite}" != "${TEST_CNT_SQL}" ]; then - echo -e "[ERROR] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} failed.\nget_sqlite=${result_cnt_sqlite}, want=${TEST_CNT_SQL}" - exit 1 -fi -echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} passed." echo "[INFO] ${GPBACKMAN_TEST_COMMAND} all tests passed" exit 0 diff --git a/e2e_tests/scripts/run_backup-delete.sh b/e2e_tests/scripts/run_backup-delete.sh index fec25b6..731e836 100755 --- a/e2e_tests/scripts/run_backup-delete.sh +++ b/e2e_tests/scripts/run_backup-delete.sh @@ -40,12 +40,16 @@ TIMESTAMP="20230724090000" gpbackman ${GPBACKMAN_TEST_COMMAND} \ --history-file ${WORK_DIR}/gpbackup_history_metadata_plugin.yaml \ --timestamp ${TIMESTAMP} \ ---plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml +--plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml \ +--force \ +--ignore-errors gpbackman ${GPBACKMAN_TEST_COMMAND} \ --history-db ${WORK_DIR}/gpbackup_history.db \ --timestamp ${TIMESTAMP} \ ---plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml +--plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml \ +--force \ +--ignore-errors GPBACKMAN_RESULT_YAML=$(gpbackman backup-info \ --history-file ${WORK_DIR}/gpbackup_history_metadata_plugin.yaml \ @@ -84,58 +88,7 @@ gpbackman ${GPBACKMAN_TEST_COMMAND} \ --history-db ${WORK_DIR}/gpbackup_history.db \ --timestamp ${TIMESTAMP} \ --plugin-config ${HOME_DIR}/gpbackup_s3_plugin.yaml \ ---cascade - -GPBACKMAN_RESULT_SQLITE=$(gpbackman backup-info \ ---history-db ${WORK_DIR}/gpbackup_history.db \ ---deleted) - -echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID}." -result_cnt_sqlite=$(echo "${GPBACKMAN_RESULT_SQLITE}" | cut -f9 -d'|' | awk '{$1=$1};1' | grep -E ${DATE_REGEX} | wc -l) -if [ "${result_cnt_sqlite}" != "${TEST_CNT}" ]; then - echo -e "[ERROR] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} failed.\nget_sqlite=${result_cnt_sqlite}, want=${TEST_CNT}" - exit 1 -fi -echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} passed." - -################################################################ -# Test 3. -# Test errors in logs. -TEST_ID="3" - -TIMESTAMP="20230725101959" -TEST_CNT=5 - -echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID}." -logs_errors=$(grep -r ERROR ${HOME_DIR}/gpAdminLogs/) -if [ $? == 0 ]; then - echo -e "[ERROR] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} failed.\nget_logs:\n${logs_errors}" - exit 1 -fi -echo "[INFO] ${GPBACKMAN_TEST_COMMAND} test ${TEST_ID} passed." - -################################################################ -# Test 4. -# Test ignore errors option. - -TEST_ID="4" - -# After previous tests, in history there should be 6 backup with dete deleted info. -# In this test we use plugin config with invalid aws_access_key_id for s3. -# The error occurs: -# InvalidAccessKeyId: The Access Key Id you provided does not exist in our records. -# -# With --force and --ignore-errors, the error that occurs is ignored and the backup is marked as deleted. -TEST_CNT=7 - -TIMESTAMP="20230721090000" - -set -x -# Execute backup-delete commnad. -gpbackman ${GPBACKMAN_TEST_COMMAND} \ ---history-db ${WORK_DIR}/gpbackup_history.db \ ---timestamp ${TIMESTAMP} \ ---plugin-config ${HOME_DIR}/gpbackup_s3_plugin_invalid.yaml \ +--cascade \ --force \ --ignore-errors From 1a3fe2c669e8e670d1b103a5cd1469b26cb61f98 Mon Sep 17 00:00:00 2001 From: woblerr Date: Wed, 2 Oct 2024 00:18:56 +0300 Subject: [PATCH 4/9] Change "docker-compose" to "docker compose" in Makefile. See https://github.com/orgs/community/discussions/116610 --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 3283c3b..0105cfb 100755 --- a/Makefile +++ b/Makefile @@ -111,10 +111,10 @@ define e2e_command endef define run_docker_compose - GPBACKMAN_UID=$(UID) GPBACKMAN_GID=$(GID) docker-compose -f e2e_tests/docker-compose.yml build --force-rm --parallel ${1} - GPBACKMAN_UID=$(UID) GPBACKMAN_GID=$(GID) docker-compose -f e2e_tests/docker-compose.yml run --rm --name ${1} ${1} + GPBACKMAN_UID=$(UID) GPBACKMAN_GID=$(GID) docker compose -f e2e_tests/docker-compose.yml build --force-rm --parallel ${1} + GPBACKMAN_UID=$(UID) GPBACKMAN_GID=$(GID) docker compose -f e2e_tests/docker-compose.yml run --rm --name ${1} ${1} endef define down_docker_compose - GPBACKMAN_UID=$(UID) GPBACKMAN_GID=$(GID) docker-compose -f e2e_tests/docker-compose.yml down -v + GPBACKMAN_UID=$(UID) GPBACKMAN_GID=$(GID) docker compose -f e2e_tests/docker-compose.yml down -v endef \ No newline at end of file From 3d61e9d91d1ba6e0434506b6493e0c0a9ad39def Mon Sep 17 00:00:00 2001 From: woblerr Date: Wed, 2 Oct 2024 00:22:43 +0300 Subject: [PATCH 5/9] Fix e2e test for history-clean command. --- e2e_tests/scripts/run_history-clean.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/e2e_tests/scripts/run_history-clean.sh b/e2e_tests/scripts/run_history-clean.sh index b553cac..d478b30 100755 --- a/e2e_tests/scripts/run_history-clean.sh +++ b/e2e_tests/scripts/run_history-clean.sh @@ -34,12 +34,10 @@ gpbackman ${GPBACKMAN_TEST_COMMAND} \ --history-file ${WORK_DIR}/gpbackup_history_failure_plugin.yaml \ --history-file ${WORK_DIR}/gpbackup_history_incremental_plugin.yaml \ --before-timestamp ${TIMESTAMP} \ ---deleted gpbackman ${GPBACKMAN_TEST_COMMAND} \ --history-db ${WORK_DIR}/gpbackup_history.db \ --before-timestamp ${TIMESTAMP} \ ---deleted GPBACKMAN_RESULT_YAML=$(gpbackman backup-info \ --history-file ${WORK_DIR}/gpbackup_history_failure_plugin.yaml \ From 580aa3d188ad73670164ed2d8aacc6190fb76bc9 Mon Sep 17 00:00:00 2001 From: woblerr Date: Wed, 2 Oct 2024 01:04:04 +0300 Subject: [PATCH 6/9] Test CI. --- .github/workflows/build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11da96b..6294559 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,7 +55,14 @@ jobs: run: echo ${{ steps.buildx.outputs.platforms }} - name: Run end-to-end tests + env: + GITHUB_USER: ${{ github.actor }} + GITHUB_PKG: ${{ secrets.GUTHUB_CR_PAT }} + DOCKERHUB_USER: ${{ secrets.DOCKEHUB_USER }} + DOCKERHUB_PKG: ${{ secrets.DOCKEHUB_TOKEN }} run: | + echo ${GITHUB_PKG} | docker login ghcr.io -u ${GITHUB_USER} --password-stdin + echo ${DOCKERHUB_PKG} | docker login -u ${DOCKERHUB_USER} --password-stdin make test-e2e - name: Build image and push master tag to ghcr.io and Docker Hub From b063355a2ef027e8c6aec58f817bf8d207868586 Mon Sep 17 00:00:00 2001 From: woblerr Date: Wed, 2 Oct 2024 15:56:04 +0300 Subject: [PATCH 7/9] Fix some warnings. --- .github/workflows/build.yml | 7 ------- e2e_tests/conf/Dockerfile.s3_plugin | 2 +- e2e_tests/docker-compose.yml | 2 -- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6294559..11da96b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,14 +55,7 @@ jobs: run: echo ${{ steps.buildx.outputs.platforms }} - name: Run end-to-end tests - env: - GITHUB_USER: ${{ github.actor }} - GITHUB_PKG: ${{ secrets.GUTHUB_CR_PAT }} - DOCKERHUB_USER: ${{ secrets.DOCKEHUB_USER }} - DOCKERHUB_PKG: ${{ secrets.DOCKEHUB_TOKEN }} run: | - echo ${GITHUB_PKG} | docker login ghcr.io -u ${GITHUB_USER} --password-stdin - echo ${DOCKERHUB_PKG} | docker login -u ${DOCKERHUB_USER} --password-stdin make test-e2e - name: Build image and push master tag to ghcr.io and Docker Hub diff --git a/e2e_tests/conf/Dockerfile.s3_plugin b/e2e_tests/conf/Dockerfile.s3_plugin index 2a51bab..8d5e780 100644 --- a/e2e_tests/conf/Dockerfile.s3_plugin +++ b/e2e_tests/conf/Dockerfile.s3_plugin @@ -14,5 +14,5 @@ RUN apk add --no-cache --update build-base bash perl \ && cd /tmp/gpbackup-s3-plugin \ && make build -FROM gpbackman as gpbackman-plugins +FROM gpbackman AS gpbackman-plugins COPY --from=s3_plugin-builder /go/bin/gpbackup_s3_plugin /home/gpbackman/gpbackup_s3_plugin diff --git a/e2e_tests/docker-compose.yml b/e2e_tests/docker-compose.yml index df3d39d..7dd4097 100644 --- a/e2e_tests/docker-compose.yml +++ b/e2e_tests/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: ################################################################ # Prepare infra for some tests. From e672f3470ba16149c957de726484ec91ea80794a Mon Sep 17 00:00:00 2001 From: woblerr Date: Wed, 2 Oct 2024 16:08:47 +0300 Subject: [PATCH 8/9] Disable e2e tests in CI. They will be refactored in the future. --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11da96b..5146637 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,9 +54,9 @@ jobs: - name: Available platforms run: echo ${{ steps.buildx.outputs.platforms }} - - name: Run end-to-end tests - run: | - make test-e2e + # - name: Run end-to-end tests + # run: | + # make test-e2e - name: Build image and push master tag to ghcr.io and Docker Hub if: github.event_name == 'push' && github.ref == 'refs/heads/master' From 4f5998d3d2ea9402fe27752e379c397ecbcf3394 Mon Sep 17 00:00:00 2001 From: woblerr Date: Wed, 2 Oct 2024 18:49:09 +0300 Subject: [PATCH 9/9] Update documentation. --- COMMANDS.md | 26 ++++++++++---------------- README.md | 6 +++--- cmd/history_clean.go | 4 ++-- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/COMMANDS.md b/COMMANDS.md index bcb92cd..c6b4900 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -12,10 +12,10 @@ - [Display information about backups (`backup-info`)](#display-information-about-backups-backup-info) - [Examples](#examples-2) - [Using container](#using-container-2) -- [Clean failed and deleted backups from the history database (`history-clean`)](#clean-failed-and-deleted-backups-from-the-history-database-history-clean) +- [Clean deleted backups from the history database (`history-clean`)](#clean-deleted-backups-from-the-history-database-history-clean) - [Examples](#examples-3) - - [Delete information about failed and deleted backups from history database older than n days](#delete-information-about-failed-and-deleted-backups-from-history-database-older-than-n-days) - - [Delete all backups using storage plugin older than timestamp](#delete-all-backups-using-storage-plugin-older-than-timestamp-1) + - [Delete information about deleted backups from history database older than n days](#delete-information-about-deleted-backups-from-history-database-older-than-n-days) + - [Delete information about deleted backups from history database older than timestamp](#delete-information-about-deleted-backups-from-history-database-older-than-timestamp) - [Using container](#using-container-3) - [Migrate history database (`history-migrate`)](#migrate-history-database-history-migrate) - [Examples](#examples-4) @@ -442,19 +442,17 @@ docker run \ --history-db /data/master/gpseg-1/gpbackup_history.db ``` -# Clean failed and deleted backups from the history database (`history-clean`) +# Clean deleted backups from the history database (`history-clean`) Available options for `history-clean` command and their description: ```bash ./gpbackman history-clean -h -Clean failed and deleted backups from the history database. +Clean deleted backups from the history database. Only the database is being cleaned up. -By default, information is deleted only about failed backups from gpbackup_history.db. - -To delete information about deleted backups, use the --deleted option. +Information is deleted only about deleted backups from gpbackup_history.db. Each backup must be deleted first. To delete information about backups older than the given timestamp, use the --before-timestamp option. To delete information about backups older than the given number of days, use the --older-than-day option. @@ -475,7 +473,6 @@ Usage: Flags: --before-timestamp string delete information about backups older than the given timestamp - --deleted delete information about deleted backups -h, --help help for history-clean --older-than-days uint delete information about backups older than the given number of days @@ -488,20 +485,18 @@ Global Flags: ``` ## Examples -### Delete information about failed and deleted backups from history database older than n days -Delete information about failed and deleted backups from history database older than 7 days: +### Delete information about deleted backups from history database older than n days +Delete information about deleted backups from history database older than 7 days: ```bash ./gpbackman history-clean \ --older-than-days 7 \ - --deleted ``` -### Delete all backups using storage plugin older than timestamp -Delete information about failed and deleted backups from history database older than timestamp `20240101100000`: +### Delete information about deleted backups from history database older than timestamp +Delete information about deleted backups from history database older than timestamp `20240101100000`: ```bash ./gpbackman history-clean \ --before-timestamp 20240101100000 \ - --deleted ``` ## Using container @@ -517,7 +512,6 @@ docker run \ gpbackman history-clean \ --older-than-days 7 \ --history-db /data/master/gpseg-1/gpbackup_history.db \ - --deleted ``` # Migrate history database (`history-migrate`) diff --git a/README.md b/README.md index 1d7a7b1..e4bdb54 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The utility works with both history database formats: `gpbackup_history.yaml` fi * display the backup report for existing backups; * delete existing backups from local storage or using storage plugins (for example, [S3 Storage Plugin](https://github.com/greenplum-db/gpbackup-s3-plugin)); * delete all existing backups from local storage or using storage plugins older than the specified time condition; -* clean failed and deleted backups from the history database; +* clean deleted backups from the history database; * migrate history database from `gpbackup_history.yaml` format to `gpbackup_history.db` SQLite format. ## Commands @@ -34,7 +34,7 @@ Available Commands: backup-info Display information about backups completion Generate the autocompletion script for the specified shell help Help about any command - history-clean Clean failed and deleted backups from the history database + history-clean Clean deleted backups from the history database history-migrate Migrate history database report-info Display the report for a specific backup @@ -56,7 +56,7 @@ Description of each command: * [Delete all existing backups older than the specified time condition (`backup-clean`)](./COMMANDS.md#delete-all-existing-backups-older-than-the-specified-time-condition-backup-clean) * [Delete a specific existing backup (`backup-delete`)](./COMMANDS.md#delete-a-specific-existing-backup-backup-delete) * [Display information about backups (`backup-info`)](./COMMANDS.md#display-information-about-backups-backup-info) -* [Clean failed and deleted backups from the history database (`history-clean`)](./COMMANDS.md#clean-failed-and-deleted-backups-from-the-history-database-history-clean) +* [Clean deleted backups from the history database (`history-clean`)](./COMMANDS.md#clean-deleted-backups-from-the-history-database-history-clean) * [Migrate history database (`history-migrate`)](./COMMANDS.md#migrate-history-database-history-migrate) * [Display the report for a specific backup (`report-info`)](./COMMANDS.md#display-the-report-for-a-specific-backup-report-info) diff --git a/cmd/history_clean.go b/cmd/history_clean.go index 41db7a0..dee68bd 100644 --- a/cmd/history_clean.go +++ b/cmd/history_clean.go @@ -18,8 +18,8 @@ var ( var historyCleanCmd = &cobra.Command{ Use: "history-clean", - Short: "Clean failed and deleted backups from the history database", - Long: `Clean failed and deleted backups from the history database. + Short: "Clean deleted backups from the history database", + Long: `Clean deleted backups from the history database. Only the database is being cleaned up. Information is deleted only about deleted backups from gpbackup_history.db. Each backup must be deleted first.