diff --git a/.chloggen/grpc-extension-context.yaml b/.chloggen/grpc-extension-context.yaml new file mode 100644 index 00000000000..652a3b2381b --- /dev/null +++ b/.chloggen/grpc-extension-context.yaml @@ -0,0 +1,11 @@ +change_type: bug_fix + +component: pkg/extensionmiddleware + +note: Add context.Context to gRPC middleware interface constructors. + +subtext: This is a breaking API change for components that implement or use extensionmiddleware. + +issues: [14523] + +change_logs: [api] diff --git a/.chloggen/grpc-middlware-context.yaml b/.chloggen/grpc-middlware-context.yaml new file mode 100644 index 00000000000..e0972c8894e --- /dev/null +++ b/.chloggen/grpc-middlware-context.yaml @@ -0,0 +1,9 @@ +change_type: bug_fix + +component: pkg/config/configmiddleware + +note: Add context.Context to gRPC middleware interface constructors. + +issues: [14523] + +change_logs: [api] diff --git a/config/configgrpc/client_middleware_test.go b/config/configgrpc/client_middleware_test.go index 7ddb99ba164..58fedd60900 100644 --- a/config/configgrpc/client_middleware_test.go +++ b/config/configgrpc/client_middleware_test.go @@ -40,7 +40,7 @@ func newTestMiddlewareConfig(name string) configmiddleware.Config { func newTestClientMiddleware(name string) extension.Extension { return &testClientMiddleware{ Extension: extensionmiddlewaretest.NewNop(), - GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { + GetGRPCClientOptionsFunc: func(_ context.Context) ([]grpc.DialOption, error) { return []grpc.DialOption{ grpc.WithChainUnaryInterceptor( func( diff --git a/config/configgrpc/server_middleware_test.go b/config/configgrpc/server_middleware_test.go index c62748c78be..3512445fa49 100644 --- a/config/configgrpc/server_middleware_test.go +++ b/config/configgrpc/server_middleware_test.go @@ -46,7 +46,7 @@ type testServerMiddleware struct { func newTestServerMiddleware(name string) extension.Extension { return &testServerMiddleware{ Extension: extensionmiddlewaretest.NewNop(), - GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { + GetGRPCServerOptionsFunc: func(_ context.Context) ([]grpc.ServerOption, error) { return []grpc.ServerOption{grpc.ChainUnaryInterceptor( func( ctx context.Context, diff --git a/config/configmiddleware/configmiddleware.go b/config/configmiddleware/configmiddleware.go index 831ba7766fe..a41f46af8dc 100644 --- a/config/configmiddleware/configmiddleware.go +++ b/config/configmiddleware/configmiddleware.go @@ -68,10 +68,10 @@ func (m Config) GetHTTPServerHandler(_ context.Context, extensions map[component // extensionmiddleware.GRPCClient from the map of extensions, and // returns the gRPC dial options. If a middleware is not found, an // error is returned. This should only be used by gRPC clients. -func (m Config) GetGRPCClientOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.DialOption, error) { +func (m Config) GetGRPCClientOptions(ctx context.Context, extensions map[component.ID]component.Component) ([]grpc.DialOption, error) { if ext, found := extensions[m.ID]; found { if client, ok := ext.(extensionmiddleware.GRPCClient); ok { - return client.GetGRPCClientOptions() + return client.GetGRPCClientOptions(ctx) } return nil, errNotGRPCClient } @@ -82,10 +82,10 @@ func (m Config) GetGRPCClientOptions(_ context.Context, extensions map[component // extensionmiddleware.GRPCServer from the map of extensions, and // returns the gRPC server options. If a middleware is not found, an // error is returned. This should only be used by gRPC servers. -func (m Config) GetGRPCServerOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.ServerOption, error) { +func (m Config) GetGRPCServerOptions(ctx context.Context, extensions map[component.ID]component.Component) ([]grpc.ServerOption, error) { if ext, found := extensions[m.ID]; found { if server, ok := ext.(extensionmiddleware.GRPCServer); ok { - return server.GetGRPCServerOptions() + return server.GetGRPCServerOptions(ctx) } return nil, errNotGRPCServer } diff --git a/config/configmiddleware/configmiddleware_test.go b/config/configmiddleware/configmiddleware_test.go index 5cdb2628fba..7551f5346ec 100644 --- a/config/configmiddleware/configmiddleware_test.go +++ b/config/configmiddleware/configmiddleware_test.go @@ -149,7 +149,7 @@ func TestConfig_GetGRPCServerOptions(t *testing.T) { extensionmiddleware.GetGRPCServerOptionsFunc }{ Extension: extensionmiddlewaretest.NewNop(), - GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { + GetGRPCServerOptionsFunc: func(context.Context) ([]grpc.ServerOption, error) { return []grpc.ServerOption{ grpc.EmptyServerOption{}, }, nil @@ -212,7 +212,7 @@ func TestConfig_GetGRPCClientOptions(t *testing.T) { extensionmiddleware.GetGRPCClientOptionsFunc }{ Extension: extensionmiddlewaretest.NewNop(), - GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { + GetGRPCClientOptionsFunc: func(_ context.Context) ([]grpc.DialOption, error) { return []grpc.DialOption{ grpc.EmptyDialOption{}, }, nil diff --git a/extension/extensionmiddleware/client.go b/extension/extensionmiddleware/client.go index fb24a18339e..547c74b4486 100644 --- a/extension/extensionmiddleware/client.go +++ b/extension/extensionmiddleware/client.go @@ -4,6 +4,7 @@ package extensionmiddleware // import "go.opentelemetry.io/collector/extension/extensionmiddleware" import ( + "context" "net/http" "google.golang.org/grpc" @@ -18,7 +19,7 @@ type HTTPClient interface { // GRPCClient is an interface for gRPC client middleware extensions. type GRPCClient interface { // GetGRPCClientOptions returns the gRPC dial options to use for client connections. - GetGRPCClientOptions() ([]grpc.DialOption, error) + GetGRPCClientOptions(context.Context) ([]grpc.DialOption, error) } var _ HTTPClient = (*GetHTTPRoundTripperFunc)(nil) @@ -36,11 +37,11 @@ func (f GetHTTPRoundTripperFunc) GetHTTPRoundTripper(base http.RoundTripper) (ht var _ GRPCClient = (*GetGRPCClientOptionsFunc)(nil) // GetGRPCClientOptionsFunc is a function that implements GRPCClient. -type GetGRPCClientOptionsFunc func() ([]grpc.DialOption, error) +type GetGRPCClientOptionsFunc func(context.Context) ([]grpc.DialOption, error) -func (f GetGRPCClientOptionsFunc) GetGRPCClientOptions() ([]grpc.DialOption, error) { +func (f GetGRPCClientOptionsFunc) GetGRPCClientOptions(ctx context.Context) ([]grpc.DialOption, error) { if f == nil { return nil, nil } - return f() + return f(ctx) } diff --git a/extension/extensionmiddleware/client_test.go b/extension/extensionmiddleware/client_test.go index 8d4eadcade2..9161e6236f7 100644 --- a/extension/extensionmiddleware/client_test.go +++ b/extension/extensionmiddleware/client_test.go @@ -4,6 +4,7 @@ package extensionmiddleware import ( + "context" "errors" "net/http" "testing" @@ -46,44 +47,42 @@ func TestGetHTTPRoundTripperFunc(t *testing.T) { } func TestGetGRPCClientOptionsFunc(t *testing.T) { + type testCtx struct{} + var ( + key = testCtx{} + value = "testval" + ) + testctx := context.WithValue(context.Background(), key, value) + t.Run("nil function", func(t *testing.T) { var nilFunc GetGRPCClientOptionsFunc - options, err := nilFunc.GetGRPCClientOptions() + options, err := nilFunc.GetGRPCClientOptions(testctx) require.NoError(t, err) require.Nil(t, options) }) - t.Run("empty options function", func(t *testing.T) { - emptyFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { - return []grpc.DialOption{}, nil - }) - - options, err := emptyFunc.GetGRPCClientOptions() - require.NoError(t, err) - require.Empty(t, options) - }) - t.Run("options function", func(t *testing.T) { - // Create some test dial options dialOpt1 := grpc.WithAuthority("test-authority") dialOpt2 := grpc.WithDisableRetry() - optionsFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { + optionsFunc := GetGRPCClientOptionsFunc(func(ctx context.Context) ([]grpc.DialOption, error) { + require.Equal(t, ctx.Value(key), value) return []grpc.DialOption{dialOpt1, dialOpt2}, nil }) - options, err := optionsFunc.GetGRPCClientOptions() + options, err := optionsFunc.GetGRPCClientOptions(testctx) require.NoError(t, err) require.Len(t, options, 2) }) t.Run("error function", func(t *testing.T) { expectedErr := errors.New("grpc options error") - errorFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { + errorFunc := GetGRPCClientOptionsFunc(func(ctx context.Context) ([]grpc.DialOption, error) { + require.Equal(t, ctx.Value(key), value) return nil, expectedErr }) - options, err := errorFunc.GetGRPCClientOptions() + options, err := errorFunc.GetGRPCClientOptions(testctx) require.Error(t, err) require.Equal(t, expectedErr, err) require.Nil(t, options) diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/err.go b/extension/extensionmiddleware/extensionmiddlewaretest/err.go index b881dae2c51..262c82d0f03 100644 --- a/extension/extensionmiddleware/extensionmiddlewaretest/err.go +++ b/extension/extensionmiddleware/extensionmiddlewaretest/err.go @@ -4,6 +4,7 @@ package extensionmiddlewaretest // import "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" import ( + "context" "net/http" "google.golang.org/grpc" @@ -37,13 +38,13 @@ func NewErr(err error) extension.Extension { GetHTTPRoundTripperFunc: func(http.RoundTripper) (http.RoundTripper, error) { return nil, err }, - GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { + GetGRPCClientOptionsFunc: func(context.Context) ([]grpc.DialOption, error) { return nil, err }, GetHTTPHandlerFunc: func(http.Handler) (http.Handler, error) { return nil, err }, - GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { + GetGRPCServerOptionsFunc: func(context.Context) ([]grpc.ServerOption, error) { return nil, err }, } diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go b/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go index 14bcf291b5b..0ebbbf3ba64 100644 --- a/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go +++ b/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go @@ -4,6 +4,7 @@ package extensionmiddlewaretest import ( + "context" "errors" "testing" @@ -22,7 +23,7 @@ func TestErrClient(t *testing.T) { grpcClient, ok := client.(extensionmiddleware.GRPCClient) require.True(t, ok) - _, err = grpcClient.GetGRPCClientOptions() + _, err = grpcClient.GetGRPCClientOptions(context.Background()) require.Error(t, err) } @@ -36,6 +37,6 @@ func TestErrServer(t *testing.T) { grpcServer, ok := server.(extensionmiddleware.GRPCServer) require.True(t, ok) - _, err = grpcServer.GetGRPCServerOptions() + _, err = grpcServer.GetGRPCServerOptions(context.Background()) require.Error(t, err) } diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go b/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go index d1190fbff98..6146ee7eceb 100644 --- a/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go +++ b/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go @@ -4,6 +4,7 @@ package extensionmiddlewaretest import ( + "context" "net/http" "testing" @@ -23,7 +24,7 @@ func TestNopClient(t *testing.T) { grpcClient, ok := client.(extensionmiddleware.GRPCClient) require.True(t, ok) - grpcOpts, err := grpcClient.GetGRPCClientOptions() + grpcOpts, err := grpcClient.GetGRPCClientOptions(context.Background()) require.NoError(t, err) require.Nil(t, grpcOpts) } @@ -39,7 +40,7 @@ func TestNopServer(t *testing.T) { grpcServer, ok := client.(extensionmiddleware.GRPCServer) require.True(t, ok) - grpcOpts, err := grpcServer.GetGRPCServerOptions() + grpcOpts, err := grpcServer.GetGRPCServerOptions(context.Background()) require.NoError(t, err) require.Nil(t, grpcOpts) } diff --git a/extension/extensionmiddleware/server.go b/extension/extensionmiddleware/server.go index 6fa9ca1ae60..6cb280eb7ea 100644 --- a/extension/extensionmiddleware/server.go +++ b/extension/extensionmiddleware/server.go @@ -4,6 +4,7 @@ package extensionmiddleware // import "go.opentelemetry.io/collector/extension/extensionmiddleware" import ( + "context" "net/http" "google.golang.org/grpc" @@ -18,7 +19,7 @@ type HTTPServer interface { // GRPCServer defines the interface for gRPC server middleware extensions. type GRPCServer interface { // GetGRPCServerOptions returns options for a gRPC server. - GetGRPCServerOptions() ([]grpc.ServerOption, error) + GetGRPCServerOptions(context.Context) ([]grpc.ServerOption, error) } var _ HTTPServer = (*GetHTTPHandlerFunc)(nil) @@ -36,11 +37,11 @@ func (f GetHTTPHandlerFunc) GetHTTPHandler(base http.Handler) (http.Handler, err var _ GRPCServer = (*GetGRPCServerOptionsFunc)(nil) // GetGRPCServerOptionsFunc is a function that implements GRPCServer. -type GetGRPCServerOptionsFunc func() ([]grpc.ServerOption, error) +type GetGRPCServerOptionsFunc func(context.Context) ([]grpc.ServerOption, error) -func (f GetGRPCServerOptionsFunc) GetGRPCServerOptions() ([]grpc.ServerOption, error) { +func (f GetGRPCServerOptionsFunc) GetGRPCServerOptions(ctx context.Context) ([]grpc.ServerOption, error) { if f == nil { return nil, nil } - return f() + return f(ctx) } diff --git a/extension/extensionmiddleware/server_test.go b/extension/extensionmiddleware/server_test.go index eee61f5410e..14d6ed5c4a6 100644 --- a/extension/extensionmiddleware/server_test.go +++ b/extension/extensionmiddleware/server_test.go @@ -66,9 +66,16 @@ func TestGetHTTPHandlerFunc(t *testing.T) { } func TestGetGRPCServerOptionsFunc(t *testing.T) { + type testCtx struct{} + var ( + key = testCtx{} + value = "testval" + ) + testctx := context.WithValue(context.Background(), key, value) + t.Run("nil_function", func(t *testing.T) { var f GetGRPCServerOptionsFunc - opts, err := f.GetGRPCServerOptions() + opts, err := f.GetGRPCServerOptions(testctx) require.NoError(t, err) require.Nil(t, opts) }) @@ -84,22 +91,24 @@ func TestGetGRPCServerOptionsFunc(t *testing.T) { } expectedOpts := []grpc.ServerOption{grpc.UnaryInterceptor(interceptor)} - f := GetGRPCServerOptionsFunc(func() ([]grpc.ServerOption, error) { + f := GetGRPCServerOptionsFunc(func(ctx context.Context) ([]grpc.ServerOption, error) { + require.Equal(t, ctx.Value(key), value) return expectedOpts, nil }) - opts, err := f.GetGRPCServerOptions() + opts, err := f.GetGRPCServerOptions(testctx) require.NoError(t, err) require.Equal(t, expectedOpts, opts) }) t.Run("returns_error", func(t *testing.T) { expectedErr := errors.New("test error") - f := GetGRPCServerOptionsFunc(func() ([]grpc.ServerOption, error) { + f := GetGRPCServerOptionsFunc(func(ctx context.Context) ([]grpc.ServerOption, error) { + require.Equal(t, ctx.Value(key), value) return nil, expectedErr }) - opts, err := f.GetGRPCServerOptions() + opts, err := f.GetGRPCServerOptions(testctx) require.Equal(t, expectedErr, err) require.Nil(t, opts) }) diff --git a/extension/memorylimiterextension/memorylimiter.go b/extension/memorylimiterextension/memorylimiter.go index 319c2741d82..fd86cf96234 100644 --- a/extension/memorylimiterextension/memorylimiter.go +++ b/extension/memorylimiterextension/memorylimiter.go @@ -59,7 +59,7 @@ func (ml *memoryLimiterExtension) GetHTTPHandler(base http.Handler) (http.Handle }), nil } -func (ml *memoryLimiterExtension) GetGRPCServerOptions() ([]grpc.ServerOption, error) { +func (ml *memoryLimiterExtension) GetGRPCServerOptions(_ context.Context) ([]grpc.ServerOption, error) { return []grpc.ServerOption{ grpc.ChainUnaryInterceptor( func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {