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>2023-10-20 18:57:57 +0300
committerToon Claes <toon@gitlab.com>2023-11-20 12:45:29 +0300
commita4dc75466dfebf2e583ecbf692fa0856f9952401 (patch)
tree2e399f568bfde738604e96d5e238d9f7120eee0a
parent0540fb5062304efffc5291acc533438ab7b412ec (diff)
smarthttp: Advertise bundle-uri capability
The first step toward using bundle-URI is making the server advertise it supports this capability. Insert uploadpack.advertiseBundleURIs in the git config so the info/refs response contains the bundle-uri capability. With this we also introduce the feature flag that allows us to toggle the use of bundle-URIs.
-rw-r--r--internal/bundleuri/doc.go16
-rw-r--r--internal/bundleuri/git_config.go27
-rw-r--r--internal/bundleuri/testhelper_test.go11
-rw-r--r--internal/featureflag/ff_bundle_uri.go9
-rw-r--r--internal/gitaly/service/smarthttp/inforefs.go7
-rw-r--r--internal/gitaly/service/smarthttp/inforefs_test.go100
6 files changed, 158 insertions, 12 deletions
diff --git a/internal/bundleuri/doc.go b/internal/bundleuri/doc.go
new file mode 100644
index 000000000..22a0b4957
--- /dev/null
+++ b/internal/bundleuri/doc.go
@@ -0,0 +1,16 @@
+// Package bundleuri is used to enable the use [Bundle-URI] when the client
+// clones/fetches from the repository.
+//
+// Bundle-URI is a concept in Git that allows the server to send one or more
+// URIs where [git bundles] are available. The client can download such bundles
+// to prepopulate the repository before it starts the object negotiation with
+// the server. This reduces the CPU load on the server, and the amount of
+// traffic that has to travel directly from server to client.
+//
+// This feature piggy-backs onto server-side backups. Refer to the
+// [backup documentation] how to create and store bundles on a cloud provider.
+//
+// [Bundle-URI]: https://git-scm.com/docs/bundle-uri
+// [git bundles]: https://git-scm.com/docs/git-bundle
+// [backup documentation]: https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/gitaly-backup.md
+package bundleuri
diff --git a/internal/bundleuri/git_config.go b/internal/bundleuri/git_config.go
new file mode 100644
index 000000000..2c6ab5c02
--- /dev/null
+++ b/internal/bundleuri/git_config.go
@@ -0,0 +1,27 @@
+package bundleuri
+
+import (
+ "context"
+
+ "gitlab.com/gitlab-org/gitaly/v16/internal/backup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+)
+
+// InfoRefsGitConfig return a slice of git.ConfigPairs you can inject into the
+// call to git-upload-pack(1) --advertise-refs, to advertise the use of
+// bundle-URI to the client who clones/fetches from the repository.
+func InfoRefsGitConfig(ctx context.Context) []git.ConfigPair {
+ if featureflag.BundleURI.IsDisabled(ctx) {
+ return []git.ConfigPair{}
+ }
+
+ return []git.ConfigPair{
+ {
+ Key: "uploadpack.advertiseBundleURIs",
+ Value: "true",
+ },
+ }
+}
+
diff --git a/internal/bundleuri/testhelper_test.go b/internal/bundleuri/testhelper_test.go
new file mode 100644
index 000000000..b2dd3cfea
--- /dev/null
+++ b/internal/bundleuri/testhelper_test.go
@@ -0,0 +1,11 @@
+package bundleuri
+
+import (
+ "testing"
+
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+)
+
+func TestMain(m *testing.M) {
+ testhelper.Run(m)
+}
diff --git a/internal/featureflag/ff_bundle_uri.go b/internal/featureflag/ff_bundle_uri.go
new file mode 100644
index 000000000..c912169dc
--- /dev/null
+++ b/internal/featureflag/ff_bundle_uri.go
@@ -0,0 +1,9 @@
+package featureflag
+
+// BundleURI enables the use of git's bundle URI feature
+var BundleURI = NewFeatureFlag(
+ "bundle_uri",
+ "v16.6.0",
+ "https://gitlab.com/gitlab-org/gitaly/-/issues/5656",
+ false,
+)
diff --git a/internal/gitaly/service/smarthttp/inforefs.go b/internal/gitaly/service/smarthttp/inforefs.go
index 2a01868d7..63be73f0f 100644
--- a/internal/gitaly/service/smarthttp/inforefs.go
+++ b/internal/gitaly/service/smarthttp/inforefs.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/bundleuri"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/pktline"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
@@ -62,11 +63,13 @@ func (s *server) handleInfoRefs(ctx context.Context, service, repoPath string, r
cmdOpts = append(cmdOpts, git.WithDisabledHooks())
}
- config, err := git.ConvertConfigOptions(req.GitConfigOptions)
+ gitConfig, err := git.ConvertConfigOptions(req.GitConfigOptions)
if err != nil {
return err
}
- cmdOpts = append(cmdOpts, git.WithConfig(config...))
+ gitConfig = append(gitConfig, bundleuri.InfoRefsGitConfig(ctx)...)
+
+ cmdOpts = append(cmdOpts, git.WithConfig(gitConfig...))
if _, err := pktline.WriteString(w, fmt.Sprintf("# service=git-%s\n", service)); err != nil {
return structerr.NewInternal("pktLine: %w", err)
diff --git a/internal/gitaly/service/smarthttp/inforefs_test.go b/internal/gitaly/service/smarthttp/inforefs_test.go
index ba458bac9..836dfce4a 100644
--- a/internal/gitaly/service/smarthttp/inforefs_test.go
+++ b/internal/gitaly/service/smarthttp/inforefs_test.go
@@ -33,7 +33,10 @@ import (
func TestInfoRefsUploadPack_successful(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackSuccessful)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackSuccessful)
}
func testInfoRefsUploadPackSuccessful(t *testing.T, ctx context.Context) {
@@ -63,7 +66,10 @@ func testInfoRefsUploadPackSuccessful(t *testing.T, ctx context.Context) {
func TestInfoRefsUploadPack_internalRefs(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackInternalRefs)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackInternalRefs)
}
func testInfoRefsUploadPackInternalRefs(t *testing.T, ctx context.Context) {
@@ -138,7 +144,10 @@ func testInfoRefsUploadPackInternalRefs(t *testing.T, ctx context.Context) {
func TestInfoRefsUploadPack_validate(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackValidate)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackValidate)
}
func testInfoRefsUploadPackValidate(t *testing.T, ctx context.Context) {
@@ -176,7 +185,10 @@ func testInfoRefsUploadPackValidate(t *testing.T, ctx context.Context) {
func TestInfoRefsUploadPack_partialClone(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackPartialClone)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackPartialClone)
}
func testInfoRefsUploadPackPartialClone(t *testing.T, ctx context.Context) {
@@ -204,7 +216,10 @@ func testInfoRefsUploadPackPartialClone(t *testing.T, ctx context.Context) {
func TestInfoRefsUploadPack_gitConfigOptions(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackGitConfigOptions)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackGitConfigOptions)
}
func testInfoRefsUploadPackGitConfigOptions(t *testing.T, ctx context.Context) {
@@ -230,10 +245,45 @@ func testInfoRefsUploadPackGitConfigOptions(t *testing.T, ctx context.Context) {
})
}
+func TestInfoRefsUploadPack_bundleURI(t *testing.T) {
+ t.Parallel()
+
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ ).Run(t, testInfoRefsUploadPackBundleURI)
+}
+
+func testInfoRefsUploadPackBundleURI(t *testing.T, ctx context.Context) {
+ t.Parallel()
+
+ ctx = featureflag.OutgoingCtxWithFeatureFlag(ctx, featureflag.BundleURI, true)
+
+ cfg := testcfg.Build(t)
+ cfg.SocketPath = runSmartHTTPServer(t, cfg)
+
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg)
+
+ gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch("main"), gittest.WithParents())
+
+ rpcRequest := &gitalypb.InfoRefsRequest{
+ Repository: repo,
+ GitProtocol: git.ProtocolV2,
+ GitConfigOptions: []string{"transfer.bundleURI=true"},
+ }
+ response, err := makeInfoRefsUploadPackRequest(t, ctx, cfg.SocketPath, cfg.Auth.Token, rpcRequest)
+ require.NoError(t, err)
+ requireAdvertisedCapabilitiesV2(t, string(response), "git-upload-pack", []string{
+ "bundle-uri",
+ })
+}
+
func TestInfoRefsUploadPack_gitProtocol(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackGitProtocol)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackGitProtocol)
}
func testInfoRefsUploadPackGitProtocol(t *testing.T, ctx context.Context) {
@@ -290,7 +340,10 @@ func makeInfoRefsUploadPackRequest(t *testing.T, ctx context.Context, serverSock
func TestInfoRefsReceivePack_successful(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsReceivePackSuccessful)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsReceivePackSuccessful)
}
func testInfoRefsReceivePackSuccessful(t *testing.T, ctx context.Context) {
@@ -322,7 +375,10 @@ func TestInfoRefsReceivePack_hiddenRefs(t *testing.T) {
Object pools are not yet support with WAL. This test is testing with a pooled repository.`)
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsReceivePackHiddenRefs)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsReceivePackHiddenRefs)
}
func testInfoRefsReceivePackHiddenRefs(t *testing.T, ctx context.Context) {
@@ -352,7 +408,10 @@ func testInfoRefsReceivePackHiddenRefs(t *testing.T, ctx context.Context) {
func TestInfoRefsReceivePack_validate(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsReceivePackValidate)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsReceivePackValidate)
}
func testInfoRefsReceivePackValidate(t *testing.T, ctx context.Context) {
@@ -405,6 +464,24 @@ func makeInfoRefsReceivePackRequest(t *testing.T, ctx context.Context, serverSoc
return response, err
}
+func requireAdvertisedCapabilitiesV2(t *testing.T, responseBody, expectedService string, expectedCapabilities []string) {
+ t.Helper()
+
+ responseLines := strings.SplitAfter(responseBody, "\n")
+ require.Greater(t, len(responseLines), 2)
+
+ // The first line contains the service announcement
+ require.Equal(t, gittest.Pktlinef(t, "# service=%s\n", expectedService), responseLines[0])
+
+ // The second line contains the protocol version
+ require.Equal(t, "0000"+gittest.Pktlinef(t, "version %d\n", 2), responseLines[1])
+
+ // The third line and following lines contain capabilities
+ for _, expectedCap := range expectedCapabilities {
+ require.Contains(t, responseLines[2:], gittest.Pktlinef(t, "%s\n", expectedCap))
+ }
+}
+
func requireAdvertisedRefs(t *testing.T, responseBody, expectedService string, expectedRefs []string) {
t.Helper()
@@ -444,7 +521,10 @@ func (ms *mockStreamer) PutStream(ctx context.Context, repo *gitalypb.Repository
func TestInfoRefsUploadPack_cache(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.UploadPackBoundaryBitmapTraversal).Run(t, testInfoRefsUploadPackCache)
+ testhelper.NewFeatureSets(
+ featureflag.UploadPackBoundaryBitmapTraversal,
+ featureflag.BundleURI,
+ ).Run(t, testInfoRefsUploadPackCache)
}
func testInfoRefsUploadPackCache(t *testing.T, ctx context.Context) {