diff options
Diffstat (limited to 'workhorse/internal/git/error.go')
-rw-r--r-- | workhorse/internal/git/error.go | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/workhorse/internal/git/error.go b/workhorse/internal/git/error.go index 2b7cad6bb64..86a2ba44767 100644 --- a/workhorse/internal/git/error.go +++ b/workhorse/internal/git/error.go @@ -1,4 +1,100 @@ package git +import ( + "errors" + "fmt" + "io" + + "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" + "google.golang.org/grpc/status" + + "gitlab.com/gitlab-org/gitlab/workhorse/internal/log" +) + +// For unwrapping google.golang.org/grpc/internal/status.Error +type grpcErr interface { + GRPCStatus() *status.Status + Error() string +} + // For cosmetic purposes in Sentry type copyError struct{ error } + +// handleLimitErr handles errors that come back from Gitaly that may be a +// LimitError. A LimitError is returned by Gitaly when it is at its limit in +// handling requests. Since this is a known error, we should print a sensible +// error message to the end user. +func handleLimitErr(err error, w io.Writer, f func(w io.Writer) error) { + var statusErr grpcErr + if !errors.As(err, &statusErr) { + return + } + + if st, ok := status.FromError(statusErr); ok { + details := st.Details() + for _, detail := range details { + switch detail.(type) { + case *gitalypb.LimitError: + if err := f(w); err != nil { + log.WithError(fmt.Errorf("handling limit error: %w", err)) + } + } + } + } +} + +// writeReceivePackError writes a "server is busy" error message to the +// git-recieve-pack-result. +// +// 0023\x01001aunpack server is busy +// 00000044\x2GitLab is currently unable to handle this request due to load. +// 0000 +// +// We write a line reporting that unpack failed, and then provide some progress +// information through the side-band 2 channel. +// See https://gitlab.com/gitlab-org/gitaly/-/tree/jc-return-structured-error-limits +// for more details. +func writeReceivePackError(w io.Writer) error { + if _, err := fmt.Fprintf(w, "%04x", 35); err != nil { + return err + } + + if _, err := w.Write([]byte{0x01}); err != nil { + return err + } + + if _, err := fmt.Fprintf(w, "%04xunpack server is busy\n", 26); err != nil { + return err + } + + if _, err := w.Write([]byte("0000")); err != nil { + return err + } + + if _, err := fmt.Fprintf(w, "%04x", 68); err != nil { + return err + } + + if _, err := w.Write([]byte{0x2}); err != nil { + return err + } + + if _, err := fmt.Fprint(w, "GitLab is currently unable to handle this request due to load.\n"); err != nil { + return err + } + + if _, err := w.Write([]byte("0000")); err != nil { + return err + } + + return nil +} + +// writeUploadPackError writes a "server is busy" error message that git +// understands and prints to stdout. UploadPack expects to receive pack data in +// PKT-LINE format. An error-line can be passed that begins with ERR. +// See https://git-scm.com/docs/pack-protocol/2.29.0#_pkt_line_format. +func writeUploadPackError(w io.Writer) error { + _, err := fmt.Fprintf(w, "%04xERR GitLab is currently unable to handle this request due to load.\n", 71) + return err +} |