Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Liu <jliu@gitlab.com>2023-12-12 06:54:25 +0300
committerJames Liu <jliu@gitlab.com>2024-01-15 05:40:54 +0300
commitada54fc25380ad5b6844f46df793a62075b4bb31 (patch)
tree64aaf7b2a38d7b10f424ca066b4e1a70d82cdac1
parent95bbcbcca4a2f344a171dba71f30071850f0fba6 (diff)
backup: Add RemoveRepository to the strategy
Adds a new method to the Strategy interface used by regular and server-side backups for performing repository backups and restores. This new method removes a single repository from its storage, and will eventually replace the existing RemoveAllRepositories method.
-rw-r--r--internal/backup/backup.go19
-rw-r--r--internal/backup/backup_test.go43
-rw-r--r--internal/backup/pipeline.go7
-rw-r--r--internal/backup/pipeline_test.go8
-rw-r--r--internal/backup/server_side.go19
-rw-r--r--internal/backup/server_side_test.go35
6 files changed, 131 insertions, 0 deletions
diff --git a/internal/backup/backup.go b/internal/backup/backup.go
index 5eed0724a..bb6bad6a4 100644
--- a/internal/backup/backup.go
+++ b/internal/backup/backup.go
@@ -230,6 +230,25 @@ func (mgr *Manager) RemoveAllRepositories(ctx context.Context, req *RemoveAllRep
return nil
}
+// RemoveRepository removes the specified repository from its storage.
+func (mgr *Manager) RemoveRepository(ctx context.Context, req *RemoveRepositoryRequest) error {
+ if err := setContextServerInfo(ctx, &req.Server, req.Repo.StorageName); err != nil {
+ return fmt.Errorf("remove repo: set context: %w", err)
+ }
+
+ repoClient, err := mgr.newRepoClient(ctx, req.Server)
+ if err != nil {
+ return fmt.Errorf("remove repo: create client: %w", err)
+ }
+
+ _, err = repoClient.RemoveRepository(ctx, &gitalypb.RemoveRepositoryRequest{Repository: req.Repo})
+ if err != nil {
+ return fmt.Errorf("remove repo: remove: %w", err)
+ }
+
+ return nil
+}
+
// Create creates a repository backup.
func (mgr *Manager) Create(ctx context.Context, req *CreateRequest) error {
if req.VanityRepository == nil {
diff --git a/internal/backup/backup_test.go b/internal/backup/backup_test.go
index 14341ec6a..ca92ad546 100644
--- a/internal/backup/backup_test.go
+++ b/internal/backup/backup_test.go
@@ -65,6 +65,49 @@ Issue: https://gitlab.com/gitlab-org/gitaly/-/issues/5269`)
require.NoError(t, err)
}
+func TestManager_RemoveRepository(t *testing.T) {
+ if testhelper.IsPraefectEnabled() {
+ t.Skip("local backup manager expects to operate on the local filesystem so cannot operate through praefect")
+ }
+
+ t.Parallel()
+
+ cfg := testcfg.Build(t)
+ cfg.SocketPath = testserver.RunGitalyServer(t, cfg, setup.RegisterAll)
+
+ ctx := testhelper.Context(t)
+
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg)
+ commitID := gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch("main"))
+ gittest.WriteTag(t, cfg, repoPath, "v1.0.0", commitID.Revision())
+
+ pool := client.NewPool()
+ defer testhelper.MustClose(t, pool)
+
+ backupRoot := testhelper.TempDir(t)
+ sink := backup.NewFilesystemSink(backupRoot)
+ defer testhelper.MustClose(t, sink)
+
+ locator, err := backup.ResolveLocator("pointer", sink)
+ require.NoError(t, err)
+
+ fsBackup := backup.NewManager(sink, locator, pool)
+ err = fsBackup.RemoveRepository(ctx, &backup.RemoveRepositoryRequest{
+ Server: storage.ServerInfo{Address: cfg.SocketPath, Token: cfg.Auth.Token},
+ Repo: repo,
+ })
+ require.NoError(t, err)
+ require.NoDirExists(t, repoPath)
+
+ // With an invalid repository
+ err = fsBackup.RemoveRepository(ctx, &backup.RemoveRepositoryRequest{
+ Server: storage.ServerInfo{Address: cfg.SocketPath, Token: cfg.Auth.Token},
+ Repo: &gitalypb.Repository{StorageName: "nonexistent", RelativePath: "nonexistent"},
+ })
+
+ require.EqualError(t, err, "remove repo: remove: rpc error: code = InvalidArgument desc = storage name not found")
+}
+
func TestManager_Create(t *testing.T) {
t.Parallel()
diff --git a/internal/backup/pipeline.go b/internal/backup/pipeline.go
index 8000f61af..1b969ccac 100644
--- a/internal/backup/pipeline.go
+++ b/internal/backup/pipeline.go
@@ -16,6 +16,7 @@ import (
type Strategy interface {
Create(context.Context, *CreateRequest) error
Restore(context.Context, *RestoreRequest) error
+ RemoveRepository(context.Context, *RemoveRepositoryRequest) error
RemoveAllRepositories(context.Context, *RemoveAllRepositoriesRequest) error
}
@@ -52,6 +53,12 @@ type RestoreRequest struct {
BackupID string
}
+// RemoveRepositoryRequest is a request to remove an individual repository from its storage.
+type RemoveRepositoryRequest struct {
+ Server storage.ServerInfo
+ Repo *gitalypb.Repository
+}
+
// RemoveAllRepositoriesRequest is the request to remove all repositories in the specified
// storage name.
type RemoveAllRepositoriesRequest struct {
diff --git a/internal/backup/pipeline_test.go b/internal/backup/pipeline_test.go
index 8545c905e..cd77fb5a7 100644
--- a/internal/backup/pipeline_test.go
+++ b/internal/backup/pipeline_test.go
@@ -125,6 +125,7 @@ type MockStrategy struct {
CreateFunc func(context.Context, *CreateRequest) error
RestoreFunc func(context.Context, *RestoreRequest) error
RemoveAllRepositoriesFunc func(context.Context, *RemoveAllRepositoriesRequest) error
+ RemoveRepositoryFunc func(context.Context, *RemoveRepositoryRequest) error
}
func (s MockStrategy) Create(ctx context.Context, req *CreateRequest) error {
@@ -148,6 +149,13 @@ func (s MockStrategy) RemoveAllRepositories(ctx context.Context, req *RemoveAllR
return nil
}
+func (s MockStrategy) RemoveRepository(ctx context.Context, req *RemoveRepositoryRequest) error {
+ if s.RemoveRepositoryFunc != nil {
+ return s.RemoveRepositoryFunc(ctx, req)
+ }
+ return nil
+}
+
func testPipeline(t *testing.T, init func() *Pipeline) {
strategy := MockStrategy{
CreateFunc: func(_ context.Context, req *CreateRequest) error {
diff --git a/internal/backup/server_side.go b/internal/backup/server_side.go
index 35654f215..17382e66e 100644
--- a/internal/backup/server_side.go
+++ b/internal/backup/server_side.go
@@ -112,6 +112,25 @@ func (ss ServerSideAdapter) RemoveAllRepositories(ctx context.Context, req *Remo
return nil
}
+// RemoveRepository removes the specified repository from its storage.
+func (ss ServerSideAdapter) RemoveRepository(ctx context.Context, req *RemoveRepositoryRequest) error {
+ if err := setContextServerInfo(ctx, &req.Server, req.Repo.StorageName); err != nil {
+ return fmt.Errorf("server-side remove repo: set context: %w", err)
+ }
+
+ repoClient, err := ss.newRepoClient(ctx, req.Server)
+ if err != nil {
+ return fmt.Errorf("server-side remove repo: create client: %w", err)
+ }
+
+ _, err = repoClient.RemoveRepository(ctx, &gitalypb.RemoveRepositoryRequest{Repository: req.Repo})
+ if err != nil {
+ return fmt.Errorf("server-side remove repo: remove: %w", err)
+ }
+
+ return nil
+}
+
func (ss ServerSideAdapter) newRepoClient(ctx context.Context, server storage.ServerInfo) (gitalypb.RepositoryServiceClient, error) {
conn, err := ss.pool.Dial(ctx, server.Address, server.Token)
if err != nil {
diff --git a/internal/backup/server_side_test.go b/internal/backup/server_side_test.go
index 2acc547c5..a7957bcd8 100644
--- a/internal/backup/server_side_test.go
+++ b/internal/backup/server_side_test.go
@@ -295,3 +295,38 @@ Issue: https://gitlab.com/gitlab-org/gitaly/-/issues/5269`)
})
require.NoError(t, err)
}
+
+func TestServerSideAdapter_RemoveRepository(t *testing.T) {
+ t.Parallel()
+
+ db := testdb.New(t)
+ db.TruncateAll(t)
+ datastore.NewPostgresRepositoryStore(db, map[string][]string{"virtual-storage": {"default"}})
+
+ cfg := testcfg.Build(t)
+ cfg.SocketPath = testserver.RunGitalyServer(t, cfg, setup.RegisterAll)
+
+ ctx := testhelper.Context(t)
+
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg)
+ gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch("main"))
+
+ pool := client.NewPool()
+ defer testhelper.MustClose(t, pool)
+
+ adapter := backup.NewServerSideAdapter(pool)
+ err := adapter.RemoveRepository(ctx, &backup.RemoveRepositoryRequest{
+ Server: storage.ServerInfo{Address: cfg.SocketPath, Token: cfg.Auth.Token},
+ Repo: repo,
+ })
+ require.NoError(t, err)
+ require.NoDirExists(t, repoPath)
+
+ // With an invalid repository
+ err = adapter.RemoveRepository(ctx, &backup.RemoveRepositoryRequest{
+ Server: storage.ServerInfo{Address: cfg.SocketPath, Token: cfg.Auth.Token},
+ Repo: &gitalypb.Repository{StorageName: "default", RelativePath: "nonexistent"},
+ })
+
+ require.EqualError(t, err, "server-side remove repo: remove: rpc error: code = NotFound desc = repository does not exist")
+}