From da6da6c2a60b30e06d568a8fe226c19be7c2dd47 Mon Sep 17 00:00:00 2001 From: Slach Date: Tue, 2 Jul 2024 20:18:34 +0400 Subject: [PATCH] add `clean` command to `POST /backup/actions` API handler, fix https://github.com/Altinity/clickhouse-backup/issues/945 --- ChangeLog.md | 4 +++ pkg/server/server.go | 38 ++++++++++++++++++++++++++++ test/integration/integration_test.go | 21 ++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5d35fc89..505bdafa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,7 @@ +# v2.5.18 +BUG FIXES +- add `clean` command to `POST /backup/actions` API handler, fix [945](https://github.com/Altinity/clickhouse-backup/issues/945) + # v2.5.17 BUG FIXES - Fix wrong restoration of Materialized views with view name starting with digits for `--restore-table-mapping`, fix [942](https://github.com/Altinity/clickhouse-backup/pull/942), thanks @praveenthuwat diff --git a/pkg/server/server.go b/pkg/server/server.go index 74663580..78175200 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -352,6 +352,12 @@ func (api *APIServer) actions(w http.ResponseWriter, r *http.Request) { api.writeError(w, http.StatusInternalServerError, row.Command, err) return } + case "clean": + actionsResults, err = api.actionsCleanHandler(w, row, command, actionsResults) + if err != nil { + api.writeError(w, http.StatusInternalServerError, row.Command, err) + return + } case "clean_remote_broken": actionsResults, err = api.actionsCleanRemoteBrokenHandler(w, row, command, actionsResults) if err != nil { @@ -453,6 +459,38 @@ func (api *APIServer) actionsKillHandler(row status.ActionRow, args []string, ac return actionsResults, nil } +func (api *APIServer) actionsCleanHandler(w http.ResponseWriter, row status.ActionRow, command string, actionsResults []actionsResultsRow) ([]actionsResultsRow, error) { + if !api.config.API.AllowParallel && status.Current.InProgress() { + api.log.Warn(ErrAPILocked.Error()) + return actionsResults, ErrAPILocked + } + commandId, ctx := status.Current.Start(command) + cfg, err := api.ReloadConfig(w, "clean") + if err != nil { + status.Current.Stop(commandId, err) + return actionsResults, err + } + b := backup.NewBackuper(cfg) + err = b.Clean(ctx) + if err != nil { + api.log.Errorf("actions Clean error: %v", err) + status.Current.Stop(commandId, err) + return actionsResults, err + } + api.log.Info("CLEANED") + go func() { + if metricsErr := api.UpdateBackupMetrics(context.Background(), true); metricsErr != nil { + api.log.Errorf("UpdateBackupMetrics return error: %v", metricsErr) + } + }() + status.Current.Stop(commandId, nil) + actionsResults = append(actionsResults, actionsResultsRow{ + Status: "success", + Operation: row.Command, + }) + return actionsResults, nil +} + func (api *APIServer) actionsCleanRemoteBrokenHandler(w http.ResponseWriter, row status.ActionRow, command string, actionsResults []actionsResultsRow) ([]actionsResultsRow, error) { if !api.config.API.AllowParallel && status.Current.InProgress() { api.log.Warn(ErrAPILocked.Error()) diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index 38eec179..4eaf5f90 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -729,6 +729,8 @@ func TestServerAPI(t *testing.T) { testAPIBackupDelete(r) + testAPIBackupClean(r, ch) + r.NoError(dockerExec("clickhouse-backup", "pkill", "-n", "-f", "clickhouse-backup")) r.NoError(ch.dropDatabase("long_schema")) } @@ -880,7 +882,24 @@ func testAPIBackupDelete(r *require.Assertions) { } -func testAPIMetrics(r *require.Assertions, ch *TestClickHouse) { +func testAPIBackupClean(r *require.Assertions, ch *TestClickHouse) { + log.Info("Check /backup/clean/ /backup/clean_remote_broken/ and /backup/actions fot these two commands") + out, err := dockerExecOut("clickhouse-backup", "bash", "-ce", fmt.Sprintf("curl -sfL -XPOST 'http://localhost:7171/backup/clean'")) + log.Infof(out) + r.NoError(err) + r.NotContains(out, "another operation is currently running") + r.NotContains(out, "\"status\":\"error\"") + + out, err = dockerExecOut("clickhouse-backup", "bash", "-ce", fmt.Sprintf("curl -sfL -XPOST 'http://localhost:7171/backup/clean/remote_broken'")) + log.Infof(out) + r.NoError(err) + r.NotContains(out, "another operation is currently running") + r.NotContains(out, "\"status\":\"error\"") + + runClickHouseClientInsertSystemBackupActions(r, ch, []string{"clean","clean_remote_broken"}, false) +} + + func testAPIMetrics(r *require.Assertions, ch *TestClickHouse) { log.Info("Check /metrics clickhouse_backup_last_backup_size_remote") var lastRemoteSize int64 r.NoError(ch.chbackend.SelectSingleRowNoCtx(&lastRemoteSize, "SELECT size FROM system.backup_list WHERE name='z_backup_5' AND location='remote'"))