diff options
Diffstat (limited to 'internal/handler/exec.go')
-rw-r--r-- | internal/handler/exec.go | 114 |
1 files changed, 34 insertions, 80 deletions
diff --git a/internal/handler/exec.go b/internal/handler/exec.go index 9bd8018..44b02a7 100644 --- a/internal/handler/exec.go +++ b/internal/handler/exec.go @@ -6,56 +6,57 @@ import ( "strconv" "strings" - grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" grpccodes "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" grpcstatus "google.golang.org/grpc/status" "gitlab.com/gitlab-org/gitlab-shell/internal/config" + "gitlab.com/gitlab-org/gitlab-shell/internal/gitaly" "gitlab.com/gitlab-org/gitlab-shell/internal/gitlabnet/accessverifier" "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv" - gitalyauth "gitlab.com/gitlab-org/gitaly/v14/auth" - "gitlab.com/gitlab-org/gitaly/v14/client" pb "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" - "gitlab.com/gitlab-org/labkit/correlation" - grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc" "gitlab.com/gitlab-org/labkit/log" - grpctracing "gitlab.com/gitlab-org/labkit/tracing/grpc" ) // GitalyHandlerFunc implementations are responsible for making // an appropriate Gitaly call using the provided client and context // and returning an error from the Gitaly call. -type GitalyHandlerFunc func(ctx context.Context, client *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) +type GitalyHandlerFunc func(ctx context.Context, client *grpc.ClientConn) (int32, error) type GitalyCommand struct { - Config *config.Config - ServiceName string - Address string - Token string - Features map[string]string - DialSidechannel bool + Config *config.Config + Response *accessverifier.Response + Command gitaly.Command +} + +func NewGitalyCommand(cfg *config.Config, serviceName string, response *accessverifier.Response) *GitalyCommand { + gc := gitaly.Command{ + ServiceName: serviceName, + Address: response.Gitaly.Address, + Token: response.Gitaly.Token, + DialSidechannel: response.Gitaly.UseSidechannel, + } + + return &GitalyCommand{Config: cfg, Response: response, Command: gc} } // RunGitalyCommand provides a bootstrap for Gitaly commands executed // through GitLab-Shell. It ensures that logging, tracing and other // common concerns are configured before executing the `handler`. func (gc *GitalyCommand) RunGitalyCommand(ctx context.Context, handler GitalyHandlerFunc) error { - registry := client.NewSidechannelRegistry(log.ContextLogger(ctx)) - conn, err := getConn(ctx, gc, registry) + // We leave the connection open for future reuse + conn, err := gc.getConn(ctx) if err != nil { log.ContextLogger(ctx).WithError(fmt.Errorf("RunGitalyCommand: %v", err)).Error("Failed to get connection to execute Git command") return err } - defer conn.Close() - childCtx := withOutgoingMetadata(ctx, gc.Features) + childCtx := withOutgoingMetadata(ctx, gc.Response.Gitaly.Features) ctxlog := log.ContextLogger(childCtx) - exitStatus, err := handler(childCtx, conn, registry) + exitStatus, err := handler(childCtx, conn) if err != nil { if grpcstatus.Convert(err).Code() == grpccodes.Unavailable { @@ -72,35 +73,35 @@ func (gc *GitalyCommand) RunGitalyCommand(ctx context.Context, handler GitalyHan // PrepareContext wraps a given context with a correlation ID and logs the command to // be run. -func (gc *GitalyCommand) PrepareContext(ctx context.Context, repository *pb.Repository, response *accessverifier.Response, env sshenv.Env) (context.Context, context.CancelFunc) { +func (gc *GitalyCommand) PrepareContext(ctx context.Context, repository *pb.Repository, env sshenv.Env) (context.Context, context.CancelFunc) { ctx, cancel := context.WithCancel(ctx) - gc.LogExecution(ctx, repository, response, env) + gc.LogExecution(ctx, repository, env) md, ok := metadata.FromOutgoingContext(ctx) if !ok { md = metadata.New(nil) } - md.Append("key_id", strconv.Itoa(response.KeyId)) - md.Append("key_type", response.KeyType) - md.Append("user_id", response.UserId) - md.Append("username", response.Username) + md.Append("key_id", strconv.Itoa(gc.Response.KeyId)) + md.Append("key_type", gc.Response.KeyType) + md.Append("user_id", gc.Response.UserId) + md.Append("username", gc.Response.Username) md.Append("remote_ip", env.RemoteAddr) ctx = metadata.NewOutgoingContext(ctx, md) return ctx, cancel } -func (gc *GitalyCommand) LogExecution(ctx context.Context, repository *pb.Repository, response *accessverifier.Response, env sshenv.Env) { +func (gc *GitalyCommand) LogExecution(ctx context.Context, repository *pb.Repository, env sshenv.Env) { fields := log.Fields{ - "command": gc.ServiceName, + "command": gc.Command.ServiceName, "gl_project_path": repository.GlProjectPath, "gl_repository": repository.GlRepository, - "user_id": response.UserId, - "username": response.Username, + "user_id": gc.Response.UserId, + "username": gc.Response.Username, "git_protocol": env.GitProtocolVersion, "remote_ip": env.RemoteAddr, - "gl_key_type": response.KeyType, - "gl_key_id": response.KeyId, + "gl_key_type": gc.Response.KeyType, + "gl_key_id": gc.Response.KeyId, } log.WithContextFields(ctx, fields).Info("executing git command") @@ -118,53 +119,6 @@ func withOutgoingMetadata(ctx context.Context, features map[string]string) conte return metadata.NewOutgoingContext(ctx, md) } -func getConn(ctx context.Context, gc *GitalyCommand, registry *client.SidechannelRegistry) (*grpc.ClientConn, error) { - if gc.Address == "" { - return nil, fmt.Errorf("no gitaly_address given") - } - - serviceName := correlation.ExtractClientNameFromContext(ctx) - if serviceName == "" { - serviceName = "gitlab-shell-unknown" - - log.WithContextFields(ctx, log.Fields{"service_name": serviceName}).Warn("No gRPC service name specified, defaulting to gitlab-shell-unknown") - } - - serviceName = fmt.Sprintf("%s-%s", serviceName, gc.ServiceName) - - connOpts := client.DefaultDialOpts - connOpts = append( - connOpts, - grpc.WithStreamInterceptor( - grpc_middleware.ChainStreamClient( - grpctracing.StreamClientTracingInterceptor(), - grpc_prometheus.StreamClientInterceptor, - grpccorrelation.StreamClientCorrelationInterceptor( - grpccorrelation.WithClientName(serviceName), - ), - ), - ), - - grpc.WithUnaryInterceptor( - grpc_middleware.ChainUnaryClient( - grpctracing.UnaryClientTracingInterceptor(), - grpc_prometheus.UnaryClientInterceptor, - grpccorrelation.UnaryClientCorrelationInterceptor( - grpccorrelation.WithClientName(serviceName), - ), - ), - ), - ) - - if gc.Token != "" { - connOpts = append(connOpts, - grpc.WithPerRPCCredentials(gitalyauth.RPCCredentialsV2(gc.Token)), - ) - } - - if gc.DialSidechannel { - return client.DialSidechannel(ctx, gc.Address, registry, connOpts) - } - - return client.DialContext(ctx, gc.Address, connOpts) +func (gc *GitalyCommand) getConn(ctx context.Context) (*grpc.ClientConn, error) { + return gc.Config.GitalyClient.GetConnection(ctx, gc.Command) } |