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:
authorToon Claes <toon@gitlab.com>2021-09-20 11:21:57 +0300
committerToon Claes <toon@gitlab.com>2021-09-20 11:21:57 +0300
commite38c2b3add636eadb6b62148d5086a72a2f9cd3f (patch)
treeb20faa2c3d76b4a51d5e8f78169bc7b3540ce04e
parentec75cf8b08b74572068e2961ef212e5b97a97917 (diff)
parent8240393ca21cd48287cfcf54fc6a7c2c97394b12 (diff)
Merge branch 'fix_restore_into_non_existent' into 'master'
Allow restoring into a non-existent repo on praefect Closes #3775 See merge request gitlab-org/gitaly!3865
-rw-r--r--internal/backup/backup.go6
-rw-r--r--internal/backup/backup_test.go144
-rw-r--r--internal/git/gittest/repo.go6
3 files changed, 135 insertions, 21 deletions
diff --git a/internal/backup/backup.go b/internal/backup/backup.go
index 33eba0d69..70a9b6d91 100644
--- a/internal/backup/backup.go
+++ b/internal/backup/backup.go
@@ -226,7 +226,11 @@ func (mgr *Manager) removeRepository(ctx context.Context, server storage.ServerI
if err != nil {
return fmt.Errorf("remove repository: %w", err)
}
- if _, err := repoClient.RemoveRepository(ctx, &gitalypb.RemoveRepositoryRequest{Repository: repo}); err != nil {
+ _, err = repoClient.RemoveRepository(ctx, &gitalypb.RemoveRepositoryRequest{Repository: repo})
+ switch {
+ case status.Code(err) == codes.NotFound:
+ return nil
+ case err != nil:
return fmt.Errorf("remove repository: %w", err)
}
return nil
diff --git a/internal/backup/backup_test.go b/internal/backup/backup_test.go
index 081d21f28..425656435 100644
--- a/internal/backup/backup_test.go
+++ b/internal/backup/backup_test.go
@@ -6,13 +6,21 @@ import (
"fmt"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"testing"
+ "time"
+ "github.com/pelletier/go-toml"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v14/client"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/config"
+ gitalylog "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/config/log"
"gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/setup"
"gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/storage"
+ praefectConfig "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/config"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/datastore/glsql"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper/testserver"
@@ -131,25 +139,119 @@ func TestManager_Restore(t *testing.T) {
gitalyAddr := testserver.RunGitalyServer(t, cfg, nil, setup.RegisterAll)
+ testManagerRestore(t, cfg, gitalyAddr)
+}
+
+func TestManager_Restore_praefect(t *testing.T) {
+ gitalyCfg := testcfg.Build(t, testcfg.WithStorages("gitaly-1"))
+
+ testhelper.BuildPraefect(t, gitalyCfg)
+ testhelper.BuildGitalyHooks(t, gitalyCfg)
+
+ gitalyAddr := testserver.RunGitalyServer(t, gitalyCfg, nil, setup.RegisterAll, testserver.WithDisablePraefect())
+
+ db := glsql.NewDB(t)
+ var database string
+ require.NoError(t, db.QueryRow(`SELECT current_database()`).Scan(&database))
+ dbConf := glsql.GetDBConfig(t, database)
+
+ conf := praefectConfig.Config{
+ SocketPath: testhelper.GetTemporaryGitalySocketFileName(t),
+ VirtualStorages: []*praefectConfig.VirtualStorage{
+ {
+ Name: "default",
+ Nodes: []*praefectConfig.Node{
+ {Storage: gitalyCfg.Storages[0].Name, Address: gitalyAddr},
+ },
+ },
+ },
+ DB: dbConf,
+ Failover: praefectConfig.Failover{
+ Enabled: true,
+ ElectionStrategy: praefectConfig.ElectionStrategyPerRepository,
+ },
+ Replication: praefectConfig.DefaultReplicationConfig(),
+ Logging: gitalylog.Config{
+ Format: "json",
+ Level: "panic",
+ },
+ }
+
+ tempDir := testhelper.TempDir(t)
+ configFilePath := filepath.Join(tempDir, "config.toml")
+ configFile, err := os.Create(configFilePath)
+ require.NoError(t, err)
+ defer testhelper.MustClose(t, configFile)
+
+ require.NoError(t, toml.NewEncoder(configFile).Encode(&conf))
+ require.NoError(t, configFile.Sync())
+
+ cmd := exec.Command(filepath.Join(gitalyCfg.BinDir, "praefect"), "-config", configFilePath)
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+
+ require.NoError(t, cmd.Start())
+
+ t.Cleanup(func() { _ = cmd.Wait() })
+ t.Cleanup(func() { _ = cmd.Process.Kill() })
+
+ testManagerRestore(t, gitalyCfg, "unix://"+conf.SocketPath)
+}
+
+func testManagerRestore(t *testing.T, cfg config.Cfg, gitalyAddr string) {
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ cc, err := client.Dial(gitalyAddr, nil)
+ require.NoError(t, err)
+ defer func() { require.NoError(t, cc.Close()) }()
+ repoClient := gitalypb.NewRepositoryServiceClient(cc)
+
+ createRepo := func(t testing.TB, relativePath string) *gitalypb.Repository {
+ t.Helper()
+
+ repo := &gitalypb.Repository{
+ StorageName: "default",
+ RelativePath: relativePath,
+ }
+
+ for i := 0; true; i++ {
+ _, err := repoClient.CreateRepository(ctx, &gitalypb.CreateRepositoryRequest{Repository: repo})
+ if err != nil {
+ require.Regexp(t, "(no healthy nodes)|(no such file or directory)|(connection refused)", err.Error())
+ require.Less(t, i, 100, "praefect doesn't serve for too long")
+ time.Sleep(50 * time.Millisecond)
+ } else {
+ break
+ }
+ }
+
+ return repo
+ }
+
path := testhelper.TempDir(t)
- existingRepo, existRepoPath := gittest.CloneRepo(t, cfg, cfg.Storages[0], gittest.CloneRepoOpts{
- RelativePath: "existing_repo",
- })
- existingRepoPath := filepath.Join(path, existingRepo.RelativePath)
- existingRepoBundlePath := existingRepoPath + ".bundle"
- existingRepoCustomHooksPath := filepath.Join(existingRepoPath, "custom_hooks.tar")
- require.NoError(t, os.MkdirAll(existingRepoPath, os.ModePerm))
+ existingRepo := createRepo(t, "existing")
+ require.NoError(t, os.MkdirAll(filepath.Join(path, existingRepo.RelativePath), os.ModePerm))
+ existingRepoBundlePath := filepath.Join(path, existingRepo.RelativePath+".bundle")
+ gittest.BundleTestRepo(t, cfg, "gitlab-test.git", existingRepoBundlePath)
- gittest.Exec(t, cfg, "-C", existRepoPath, "bundle", "create", existingRepoBundlePath, "--all")
- testhelper.CopyFile(t, "../gitaly/service/repository/testdata/custom_hooks.tar", existingRepoCustomHooksPath)
+ existingRepoHooks := createRepo(t, "existing_hooks")
+ existingRepoHooksBundlePath := filepath.Join(path, existingRepoHooks.RelativePath+".bundle")
+ existingRepoHooksCustomHooksPath := filepath.Join(path, existingRepoHooks.RelativePath, "custom_hooks.tar")
+ require.NoError(t, os.MkdirAll(filepath.Join(path, existingRepoHooks.RelativePath), os.ModePerm))
+ testhelper.CopyFile(t, existingRepoBundlePath, existingRepoHooksBundlePath)
+ testhelper.CopyFile(t, "../gitaly/service/repository/testdata/custom_hooks.tar", existingRepoHooksCustomHooksPath)
- newRepo := gittest.InitRepoDir(t, cfg.Storages[0].Path, "new_repo")
- newRepoBundlePath := filepath.Join(path, newRepo.RelativePath+".bundle")
- testhelper.CopyFile(t, existingRepoBundlePath, newRepoBundlePath)
+ missingBundleRepo := createRepo(t, "missing_bundle")
+ missingBundleRepoAlwaysCreate := createRepo(t, "missing_bundle_always_create")
- missingBundleRepo := gittest.InitRepoDir(t, cfg.Storages[0].Path, "missing_bundle")
- missingBundleRepoAlwaysCreate := gittest.InitRepoDir(t, cfg.Storages[0].Path, "missing_bundle_always_create")
+ nonexistentRepo := &gitalypb.Repository{
+ StorageName: "default",
+ RelativePath: "nonexistent",
+ }
+ nonexistentRepoBundlePath := filepath.Join(path, nonexistentRepo.RelativePath+".bundle")
+ testhelper.CopyFile(t, existingRepoBundlePath, nonexistentRepoBundlePath)
for _, tc := range []struct {
desc string
@@ -160,13 +262,13 @@ func TestManager_Restore(t *testing.T) {
expectVerify bool
}{
{
- desc: "new repo, without hooks",
- repo: newRepo,
+ desc: "existing repo, without hooks",
+ repo: existingRepo,
expectVerify: true,
},
{
desc: "existing repo, with hooks",
- repo: existingRepo,
+ repo: existingRepoHooks,
expectedPaths: []string{
"custom_hooks/pre-commit.sample",
"custom_hooks/prepare-commit-msg.sample",
@@ -184,14 +286,16 @@ func TestManager_Restore(t *testing.T) {
repo: missingBundleRepoAlwaysCreate,
alwaysCreate: true,
},
+ {
+ desc: "nonexistent repo",
+ repo: nonexistentRepo,
+ expectVerify: true,
+ },
} {
t.Run(tc.desc, func(t *testing.T) {
repoPath := filepath.Join(cfg.Storages[0].Path, tc.repo.RelativePath)
bundlePath := filepath.Join(path, tc.repo.RelativePath+".bundle")
- ctx, cancel := testhelper.Context()
- defer cancel()
-
fsBackup := NewManager(NewFilesystemSink(path), LegacyLocator{})
err := fsBackup.Restore(ctx, &RestoreRequest{
Server: storage.ServerInfo{Address: gitalyAddr, Token: cfg.Auth.Token},
diff --git a/internal/git/gittest/repo.go b/internal/git/gittest/repo.go
index c05e9ce9c..6821a38fb 100644
--- a/internal/git/gittest/repo.go
+++ b/internal/git/gittest/repo.go
@@ -155,6 +155,12 @@ func CloneRepo(t testing.TB, cfg config.Cfg, storage config.Storage, opts ...Clo
return repo, absolutePath
}
+// BundleTestRepo creates a bundle of a local test repo. E.g. `gitlab-test.git`
+func BundleTestRepo(t testing.TB, cfg config.Cfg, sourceRepo, bundlePath string) {
+ repoPath := testRepositoryPath(t, sourceRepo)
+ Exec(t, cfg, "-C", repoPath, "bundle", "create", bundlePath, "--all")
+}
+
// testRepositoryPath returns the absolute path of local 'gitlab-org/gitlab-test.git' clone.
// It is cloned under the path by the test preparing step of make.
func testRepositoryPath(t testing.TB, repo string) string {