Skip to content

Commit bd5d3b2

Browse files
committed
Add ability to attach arbitrary headers
1 parent 3481845 commit bd5d3b2

File tree

1 file changed

+44
-13
lines changed

1 file changed

+44
-13
lines changed

cmd/parca-debuginfo/main.go

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import (
4343
"google.golang.org/grpc"
4444
"google.golang.org/grpc/credentials"
4545
"google.golang.org/grpc/credentials/insecure"
46+
"google.golang.org/grpc/metadata"
4647
)
4748

4849
const (
@@ -53,16 +54,17 @@ type flags struct {
5354
LogLevel string `kong:"enum='error,warn,info,debug',help='Log level.',default='info'"`
5455

5556
Upload struct {
56-
StoreAddress string `kong:"required,help='gRPC address to sends symbols to.'"`
57-
BearerToken string `kong:"help='Bearer token to authenticate with store.',env='PARCA_DEBUGINFO_BEARER_TOKEN'"`
58-
BearerTokenFile string `kong:"help='File to read bearer token from to authenticate with store.'"`
59-
Insecure bool `kong:"help='Send gRPC requests via plaintext instead of TLS.'"`
60-
InsecureSkipVerify bool `kong:"help='Skip TLS certificate verification.'"`
61-
NoExtract bool `kong:"help='Do not extract debug information from binaries, just upload the binary as is.'"`
62-
NoInitiate bool `kong:"help='Do not initiate the upload, just check if it should be initiated.'"`
63-
Force bool `kong:"help='Force upload even if the Build ID is already uploaded.'"`
64-
Type string `kong:"enum='debuginfo,executable,sources',help='Type of the debug information to upload.',default='debuginfo'"`
65-
BuildID string `kong:"help='Build ID of the binary to upload.'"`
57+
StoreAddress string `kong:"required,help='gRPC address to sends symbols to.'"`
58+
BearerToken string `kong:"help='Bearer token to authenticate with store.',env='PARCA_DEBUGINFO_BEARER_TOKEN'"`
59+
BearerTokenFile string `kong:"help='File to read bearer token from to authenticate with store.'"`
60+
Insecure bool `kong:"help='Send gRPC requests via plaintext instead of TLS.'"`
61+
InsecureSkipVerify bool `kong:"help='Skip TLS certificate verification.'"`
62+
GRPCHeaders map[string]string `kong:"help='Additional gRPC headers to send with each request (key=value pairs).'"`
63+
NoExtract bool `kong:"help='Do not extract debug information from binaries, just upload the binary as is.'"`
64+
NoInitiate bool `kong:"help='Do not initiate the upload, just check if it should be initiated.'"`
65+
Force bool `kong:"help='Force upload even if the Build ID is already uploaded.'"`
66+
Type string `kong:"enum='debuginfo,executable,sources',help='Type of the debug information to upload.',default='debuginfo'"`
67+
BuildID string `kong:"help='Build ID of the binary to upload.'"`
6668

6769
Path string `kong:"required,arg,name='path',help='Paths to upload.',type:'path'"`
6870
} `cmd:"" help:"Upload debug information files."`
@@ -429,10 +431,21 @@ func grpcConn(reg prometheus.Registerer, flags flags) (*grpc.ClientConn, error)
429431
met.EnableClientHandlingTimeHistogram()
430432
reg.MustRegister(met)
431433

434+
unaryInterceptors := []grpc.UnaryClientInterceptor{
435+
met.UnaryClientInterceptor(),
436+
}
437+
streamInterceptors := []grpc.StreamClientInterceptor{}
438+
439+
if len(flags.Upload.GRPCHeaders) > 0 {
440+
unaryInterceptors = append([]grpc.UnaryClientInterceptor{
441+
customHeadersUnaryInterceptor(flags.Upload.GRPCHeaders)}, unaryInterceptors...)
442+
streamInterceptors = append([]grpc.StreamClientInterceptor{
443+
customHeadersStreamInterceptor(flags.Upload.GRPCHeaders)}, streamInterceptors...)
444+
}
445+
432446
opts := []grpc.DialOption{
433-
grpc.WithUnaryInterceptor(
434-
met.UnaryClientInterceptor(),
435-
),
447+
grpc.WithChainUnaryInterceptor(unaryInterceptors...),
448+
grpc.WithChainStreamInterceptor(streamInterceptors...),
436449
}
437450
if flags.Upload.Insecure {
438451
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
@@ -480,6 +493,24 @@ func (t *perRequestBearerToken) RequireTransportSecurity() bool {
480493
return !t.insecure
481494
}
482495

496+
func customHeadersUnaryInterceptor(headers map[string]string) grpc.UnaryClientInterceptor {
497+
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
498+
for key, value := range headers {
499+
ctx = metadata.AppendToOutgoingContext(ctx, key, value)
500+
}
501+
return invoker(ctx, method, req, reply, cc, opts...)
502+
}
503+
}
504+
505+
func customHeadersStreamInterceptor(headers map[string]string) grpc.StreamClientInterceptor {
506+
return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
507+
for key, value := range headers {
508+
ctx = metadata.AppendToOutgoingContext(ctx, key, value)
509+
}
510+
return streamer(ctx, desc, cc, method, opts...)
511+
}
512+
}
513+
483514
func uploadViaSignedURL(ctx context.Context, url string, r io.Reader) error {
484515
req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, r)
485516
if err != nil {

0 commit comments

Comments
 (0)