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:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2021-06-22 12:03:00 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2021-06-30 13:03:46 +0300
commit67783f933b9d9a9d5c7788311c5526f61e1d3a36 (patch)
treea3e5b3656d494098393f2b330ca4aaab1bddcf83 /internal/blackbox
parent4e36ad35d4c963f3210c3cd84b5b037b7aa192bf (diff)
blackbox: Implement support for "push" probes
Implement support for "push" probes for gitaly-blackbox. These probes take as input a set of commands which specify which references are to be updated on the remote side as well as a packfile containing necessary objects to complete the request. The packfile is being provided by the user as a simple path name. While this is a bit awkward given that the user thus has to pre-generate the packfile and put it on disk somewhere, we cannot really assume that the gitaly-blackbox host has a valid Git installation and repository. It's thus not safe to say that we're able to generate the packfile on the fly. So the only alternative to having a packfile on-disk is to manually assemble the packfile via a reimplementation or to have a packfile as static data. Neither of these options seem like the right thing to do, so requiring pre-generated packfiles feels like the least-awful choice. Note that the commands are static for each probe, which essentially means that the same set of probes will be executed repeatedly. This again is a bit awkward for the user: if executing the same mutating operation multiple times, then latter executions behave differently given that the target reference is likely already at the target reference. While we could implement custom cleanup logic in gitaly-blackbox which automatically removes or resets updated references to their previous state again. For simplicity's sake, we instead put the burden one the user for now: for each probe which does a change, the user can implement a second probe which reverts the change again. Together, this provides a very simple interface which, given a packfile and a set of commands, updates remote references. Changelog: added
Diffstat (limited to 'internal/blackbox')
-rw-r--r--internal/blackbox/blackbox.go44
-rw-r--r--internal/blackbox/config.go34
2 files changed, 78 insertions, 0 deletions
diff --git a/internal/blackbox/blackbox.go b/internal/blackbox/blackbox.go
index e9259a78e..5a77ff69d 100644
--- a/internal/blackbox/blackbox.go
+++ b/internal/blackbox/blackbox.go
@@ -4,10 +4,12 @@ import (
"context"
"fmt"
"net"
+ "os"
"time"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
+ "gitlab.com/gitlab-org/gitaly/v14/internal/git"
"gitlab.com/gitlab-org/gitaly/v14/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v14/internal/version"
"gitlab.com/gitlab-org/labkit/monitoring"
@@ -149,6 +151,8 @@ func (b Blackbox) runProbes() {
switch probe.Type {
case Fetch:
err = b.fetch(probe)
+ case Push:
+ err = b.push(probe)
default:
err = fmt.Errorf("unsupported probe type: %q", probe.Type)
}
@@ -187,3 +191,43 @@ func (b Blackbox) fetch(probe Probe) error {
return nil
}
+
+func (b Blackbox) push(probe Probe) error {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ commands := make([]stats.PushCommand, len(probe.Push.Commands))
+ for i, command := range probe.Push.Commands {
+ oldOID, err := git.NewObjectIDFromHex(command.OldOID)
+ if err != nil {
+ return fmt.Errorf("invalid old object ID for probe %q: %w", probe.Name, err)
+ }
+
+ newOID, err := git.NewObjectIDFromHex(command.NewOID)
+ if err != nil {
+ return fmt.Errorf("invalid new object ID for probe %q: %w", probe.Name, err)
+ }
+
+ commands[i] = stats.PushCommand{
+ Reference: git.ReferenceName(command.Reference),
+ OldOID: oldOID,
+ NewOID: newOID,
+ }
+ }
+
+ packfile, err := os.Open(probe.Push.Packfile)
+ if err != nil {
+ return fmt.Errorf("opening packfile for probe %q: %w", probe.Name, err)
+ }
+ defer packfile.Close()
+
+ clone, err := stats.PerformHTTPPush(
+ ctx, probe.URL, probe.User, probe.Password, commands, packfile, false)
+ if err != nil {
+ return err
+ }
+
+ b.httpPostMetrics.measure(probe.Name, &clone.SendPack)
+
+ return nil
+}
diff --git a/internal/blackbox/config.go b/internal/blackbox/config.go
index 8f966c67d..46b59809e 100644
--- a/internal/blackbox/config.go
+++ b/internal/blackbox/config.go
@@ -31,8 +31,29 @@ const (
// Fetch exercises the equivalent of git-fetch(1) with measurements for packfile negotiation
// and receiving the packfile.
Fetch = ProbeType("fetch")
+ // Push exercises the equivalent of git-push(1) with measurements for packfile negotiation
+ // and sending the packfile.
+ Push = ProbeType("push")
)
+// PushCommand describes a command performed as part of the push.
+type PushCommand struct {
+ // OldOID is the old state of the reference that should be updated.
+ OldOID string `toml:"old_oid"`
+ // OldOID is the new target state of the reference that should be updated.
+ NewOID string `toml:"new_oid"`
+ // Reference is the name of the reference that should be updated.
+ Reference string `toml:"reference"`
+}
+
+// PushConfig is the configuration for a Push-type probe.
+type PushConfig struct {
+ // Commands is the list of commands which should be executed as part of the push.
+ Commands []PushCommand `toml:"commands"`
+ // Packfile is the path to the packfile that shall be sent as part of the push.
+ Packfile string `toml:"packfile"`
+}
+
// Probe is the configuration for a specific endpoint whose clone performance should be exercised.
type Probe struct {
// Name is the name of the probe. This is used both for logging and for exported
@@ -49,6 +70,8 @@ type Probe struct {
// Password is the password to authenticate with when connecting to the repository.
// Note that this password may easily leak when connecting to a non-HTTPS URL.
Password string `toml:"password"`
+ // Push contains the configuration of a Push-type probe.
+ Push *PushConfig `toml:"push"`
}
// ParseConfig parses the provided TOML-formatted configuration string and either returns the
@@ -83,6 +106,17 @@ func ParseConfig(raw string) (Config, error) {
switch probe.Type {
case "", Fetch:
probe.Type = Fetch
+ if probe.Push != nil {
+ return Config{}, fmt.Errorf("fetch probe %q cannot have push configuration", probe.Name)
+ }
+ case Push:
+ if probe.Push == nil {
+ return Config{}, fmt.Errorf("push probe %q must have push configuration", probe.Name)
+ }
+
+ if len(probe.Push.Commands) == 0 {
+ return Config{}, fmt.Errorf("push probe %q must have at least one command", probe.Name)
+ }
default:
return Config{}, fmt.Errorf("unsupported probe type: %q", probe.Type)
}