From 5f33f0f8cc0ed33165804acfa8ea5d132cebaa06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraci=20Paix=C3=A3o=20Kr=C3=B6hling?= Date: Thu, 10 Feb 2022 16:02:47 +0100 Subject: [PATCH 1/5] Implement default client authenticators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to #4558, this allows client authenticators to be created without having to implement all the functions from the ClientAuthenticator interface. This is non-breaking change. Fixes #4557 Signed-off-by: Juraci Paixão Kröhling --- .../configauth/default_clientauthenticator.go | 102 ++++++++++++++++ .../default_clientauthenticator_test.go | 112 ++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 config/configauth/default_clientauthenticator.go create mode 100644 config/configauth/default_clientauthenticator_test.go diff --git a/config/configauth/default_clientauthenticator.go b/config/configauth/default_clientauthenticator.go new file mode 100644 index 00000000000..065b2e38cd3 --- /dev/null +++ b/config/configauth/default_clientauthenticator.go @@ -0,0 +1,102 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package configauth // import "go.opentelemetry.io/collector/config/configauth" + +import ( + "context" + "net/http" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenthelper" + "google.golang.org/grpc/credentials" +) + +var _ ClientAuthenticator = (*defaultClientAuthenticator)(nil) + +// Option represents the possible options for NewServerAuthenticator. +type ClientOption func(*defaultClientAuthenticator) + +type defaultClientAuthenticator struct { + componenthelper.StartFunc + componenthelper.ShutdownFunc + roundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error) + perRPCCredentialsFunc func() (credentials.PerRPCCredentials, error) +} + +// WithClientStart overrides the default `Start` function for a component.Component. +// The default always returns nil. +func WithClientStart(startFunc componenthelper.StartFunc) ClientOption { + return func(o *defaultClientAuthenticator) { + o.StartFunc = startFunc + } +} + +// WithClientShutdown overrides the default `Shutdown` function for a component.Component. +// The default always returns nil. +func WithClientShutdown(shutdownFunc componenthelper.ShutdownFunc) ClientOption { + return func(o *defaultClientAuthenticator) { + o.ShutdownFunc = shutdownFunc + } +} + +// WithClientRoundTripper provides a `RoundTripper` function for this client authenticator. +// The default round tripper is no-op. +func WithClientRoundTripper(roundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error)) ClientOption { + return func(o *defaultClientAuthenticator) { + o.roundTripperFunc = roundTripperFunc + } +} + +// WithPerRPCCredentials provides a `PerRPCCredentials` function for this client authenticator. +// There's no default. +func WithPerRPCCredentials(perRPCCredentialsFunc func() (credentials.PerRPCCredentials, error)) ClientOption { + return func(o *defaultClientAuthenticator) { + o.perRPCCredentialsFunc = perRPCCredentialsFunc + } +} + +// NewClientAuthenticator returns a ClientAuthenticator configured with the provided options. +func NewClientAuthenticator(options ...ClientOption) ClientAuthenticator { + bc := &defaultClientAuthenticator{ + StartFunc: func(ctx context.Context, host component.Host) error { return nil }, + ShutdownFunc: func(ctx context.Context) error { return nil }, + roundTripperFunc: func(base http.RoundTripper) (http.RoundTripper, error) { return base, nil }, + perRPCCredentialsFunc: func() (credentials.PerRPCCredentials, error) { return nil, nil }, + } + + for _, op := range options { + op(bc) + } + + return bc +} + +// Start the component. +func (a *defaultClientAuthenticator) Start(ctx context.Context, host component.Host) error { + return a.StartFunc(ctx, host) +} + +// Shutdown stops the component. +func (a *defaultClientAuthenticator) Shutdown(ctx context.Context) error { + return a.ShutdownFunc(ctx) +} + +func (a *defaultClientAuthenticator) RoundTripper(base http.RoundTripper) (http.RoundTripper, error) { + return a.roundTripperFunc(base) +} + +func (a *defaultClientAuthenticator) PerRPCCredentials() (credentials.PerRPCCredentials, error) { + return a.perRPCCredentialsFunc() +} diff --git a/config/configauth/default_clientauthenticator_test.go b/config/configauth/default_clientauthenticator_test.go new file mode 100644 index 00000000000..f043b92b02a --- /dev/null +++ b/config/configauth/default_clientauthenticator_test.go @@ -0,0 +1,112 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package configauth + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/credentials" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" +) + +func TestClientDefaultValues(t *testing.T) { + // prepare + e := NewClientAuthenticator() + + // test + t.Run("start", func(t *testing.T) { + err := e.Start(context.Background(), componenttest.NewNopHost()) + assert.NoError(t, err) + }) + + t.Run("roundtripper", func(t *testing.T) { + ctx, err := e.RoundTripper(http.DefaultTransport) + assert.NotNil(t, ctx) + assert.NoError(t, err) + }) + + t.Run("shutdown", func(t *testing.T) { + err := e.Shutdown(context.Background()) + assert.NoError(t, err) + }) +} + +func TestWithClientStart(t *testing.T) { + called := false + e := NewClientAuthenticator(WithClientStart(func(c context.Context, h component.Host) error { + called = true + return nil + })) + + // test + err := e.Start(context.Background(), componenttest.NewNopHost()) + + // verify + assert.True(t, called) + assert.NoError(t, err) +} + +func TestWithClientShutdown(t *testing.T) { + called := false + e := NewClientAuthenticator(WithClientShutdown(func(c context.Context) error { + called = true + return nil + })) + + // test + err := e.Shutdown(context.Background()) + + // verify + assert.True(t, called) + assert.NoError(t, err) +} + +func TestWithClientRoundTripper(t *testing.T) { + called := false + e := NewClientAuthenticator(WithClientRoundTripper(func(base http.RoundTripper) (http.RoundTripper, error) { + called = true + return base, nil + })) + + // test + rt, err := e.RoundTripper(http.DefaultTransport) + + // verify + assert.True(t, called) + assert.NotNil(t, rt) + assert.NoError(t, err) +} + +func TestWithPerRPCCredentials(t *testing.T) { + called := false + e := NewClientAuthenticator(WithPerRPCCredentials(func() (credentials.PerRPCCredentials, error) { + called = true + return &customPerRPCCredentials{}, nil + })) + + // test + p, err := e.PerRPCCredentials() + + // verify + assert.True(t, called) + assert.NotNil(t, p) + assert.NoError(t, err) + +} From 982c75ea24e5c3406f00f5ee6932e15073a6a2bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraci=20Paix=C3=A3o=20Kr=C3=B6hling?= Date: Thu, 10 Feb 2022 16:05:03 +0100 Subject: [PATCH 2/5] Changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juraci Paixão Kröhling --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4398ccf14a..ae43cc0b074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ ### 💡 Enhancements 💡 - Add validation to check at least one endpoint is specified in otlphttpexporter's configuration (#4860) +- Implement default client authenticators (#4837) ## 🧰 Bug fixes 🧰 From 7d674cd9ef7a85e8b7b486d323db392dd9ac8342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraci=20Paix=C3=A3o=20Kr=C3=B6hling?= Date: Thu, 10 Feb 2022 16:11:11 +0100 Subject: [PATCH 3/5] lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juraci Paixão Kröhling --- config/configauth/default_clientauthenticator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/configauth/default_clientauthenticator.go b/config/configauth/default_clientauthenticator.go index 065b2e38cd3..7301424e10d 100644 --- a/config/configauth/default_clientauthenticator.go +++ b/config/configauth/default_clientauthenticator.go @@ -18,9 +18,10 @@ import ( "context" "net/http" + "google.golang.org/grpc/credentials" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenthelper" - "google.golang.org/grpc/credentials" ) var _ ClientAuthenticator = (*defaultClientAuthenticator)(nil) From 5a02401527cba7efd7e56592333f8412c1d2b820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraci=20Paix=C3=A3o=20Kr=C3=B6hling?= Date: Thu, 10 Feb 2022 16:23:18 +0100 Subject: [PATCH 4/5] Test default per-rpc-credentials implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juraci Paixão Kröhling --- config/configauth/default_clientauthenticator_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/configauth/default_clientauthenticator_test.go b/config/configauth/default_clientauthenticator_test.go index f043b92b02a..22d9e008a53 100644 --- a/config/configauth/default_clientauthenticator_test.go +++ b/config/configauth/default_clientauthenticator_test.go @@ -42,6 +42,12 @@ func TestClientDefaultValues(t *testing.T) { assert.NoError(t, err) }) + t.Run("per-rpc-credentials", func(t *testing.T) { + p, err := e.PerRPCCredentials() + assert.Nil(t, p) + assert.NoError(t, err) + }) + t.Run("shutdown", func(t *testing.T) { err := e.Shutdown(context.Background()) assert.NoError(t, err) From 7080280374eafbff140fbc685c5744c49c229c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraci=20Paix=C3=A3o=20Kr=C3=B6hling?= Date: Thu, 10 Mar 2022 15:03:30 +0100 Subject: [PATCH 5/5] Add missing godoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juraci Paixão Kröhling --- config/configauth/default_clientauthenticator.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/config/configauth/default_clientauthenticator.go b/config/configauth/default_clientauthenticator.go index 7301424e10d..c10f3398cc5 100644 --- a/config/configauth/default_clientauthenticator.go +++ b/config/configauth/default_clientauthenticator.go @@ -21,7 +21,6 @@ import ( "google.golang.org/grpc/credentials" "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/component/componenthelper" ) var _ ClientAuthenticator = (*defaultClientAuthenticator)(nil) @@ -30,15 +29,15 @@ var _ ClientAuthenticator = (*defaultClientAuthenticator)(nil) type ClientOption func(*defaultClientAuthenticator) type defaultClientAuthenticator struct { - componenthelper.StartFunc - componenthelper.ShutdownFunc + component.StartFunc + component.ShutdownFunc roundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error) perRPCCredentialsFunc func() (credentials.PerRPCCredentials, error) } // WithClientStart overrides the default `Start` function for a component.Component. // The default always returns nil. -func WithClientStart(startFunc componenthelper.StartFunc) ClientOption { +func WithClientStart(startFunc component.StartFunc) ClientOption { return func(o *defaultClientAuthenticator) { o.StartFunc = startFunc } @@ -46,7 +45,7 @@ func WithClientStart(startFunc componenthelper.StartFunc) ClientOption { // WithClientShutdown overrides the default `Shutdown` function for a component.Component. // The default always returns nil. -func WithClientShutdown(shutdownFunc componenthelper.ShutdownFunc) ClientOption { +func WithClientShutdown(shutdownFunc component.ShutdownFunc) ClientOption { return func(o *defaultClientAuthenticator) { o.ShutdownFunc = shutdownFunc } @@ -94,10 +93,12 @@ func (a *defaultClientAuthenticator) Shutdown(ctx context.Context) error { return a.ShutdownFunc(ctx) } +// RoundTripper adds the base HTTP RoundTripper in this authenticator's round tripper. func (a *defaultClientAuthenticator) RoundTripper(base http.RoundTripper) (http.RoundTripper, error) { return a.roundTripperFunc(base) } +// PerRPCCredentials returns this authenticator's credentials.PerRPCCredentials implementation. func (a *defaultClientAuthenticator) PerRPCCredentials() (credentials.PerRPCCredentials, error) { return a.perRPCCredentialsFunc() }