Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ require (
github.com/prometheus/client_golang v1.20.4
github.com/prometheus/common v0.60.1
github.com/stretchr/testify v1.9.0
golang.org/x/net v0.29.0
golang.org/x/oauth2 v0.23.0
golang.org/x/sync v0.8.0
gopkg.in/mail.v2 v2.3.1
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -97,8 +99,6 @@ require (
go.opentelemetry.io/otel/trace v1.30.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
Expand Down
45 changes: 39 additions & 6 deletions http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/benbjohnson/clock"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"golang.org/x/oauth2"

commoncfg "github.com/prometheus/common/config"

"github.com/grafana/alerting/receivers"
Expand All @@ -23,19 +25,21 @@ import (
var ErrInvalidMethod = errors.New("webhook only supports HTTP methods PUT or POST")

type clientConfiguration struct {
userAgent string
dialer net.Dialer // We use Dialer here instead of DialContext as our mqtt client doesn't support DialContext.
customDialer bool
userAgent string
dialer net.Dialer // We use Dialer here instead of DialContext as our mqtt client doesn't support DialContext.
customDialer bool
httpClientConfig HTTPClientConfig
}

// defaultDialTimeout is the default timeout for the dialer, 30 seconds to match http.DefaultTransport.
const defaultDialTimeout = 30 * time.Second

type Client struct {
cfg clientConfiguration
cfg clientConfiguration
oauth2TokenSource oauth2.TokenSource
}

func NewClient(opts ...ClientOption) *Client {
func NewClient(opts ...ClientOption) (*Client, error) {
cfg := clientConfiguration{
userAgent: "Grafana",
dialer: net.Dialer{},
Expand All @@ -49,9 +53,25 @@ func NewClient(opts ...ClientOption) *Client {
// Mostly defensive to ensure that timeout semantics don't change when given a custom dialer without a timeout.
cfg.dialer.Timeout = defaultDialTimeout
}
return &Client{

client := &Client{
cfg: cfg,
}

if cfg.httpClientConfig.OAuth2 != nil {
if err := ValidateOAuth2Config(cfg.httpClientConfig.OAuth2); err != nil {
return nil, fmt.Errorf("invalid OAuth2 configuration: %w", err)
}
// If the user has provided an OAuth2 config, we need to prepare the OAuth2 token source. This needs to
// be stored outside of the request so that the token expiration/re-use will work as expected.
tokenSource, err := NewOAuth2TokenSource(cfg)
if err != nil {
return nil, err
}
client.oauth2TokenSource = tokenSource
}

return client, nil
}

type ClientOption func(*clientConfiguration)
Expand All @@ -69,6 +89,14 @@ func WithDialer(dialer net.Dialer) ClientOption {
}
}

func WithHTTPClientConfig(config *HTTPClientConfig) ClientOption {
return func(c *clientConfiguration) {
if config != nil {
c.httpClientConfig = *config
}
}
}

func ToHTTPClientOption(option ...ClientOption) []commoncfg.HTTPClientOption {
cfg := clientConfiguration{}
for _, opt := range option {
Expand Down Expand Up @@ -140,6 +168,11 @@ func (ns *Client) SendWebhook(ctx context.Context, l log.Logger, webhook *receiv
}
}

if ns.oauth2TokenSource != nil {
level.Debug(l).Log("msg", "Adding OAuth2 roundtripper to client")
client.Transport = NewOAuth2RoundTripper(ns.oauth2TokenSource, client.Transport)
}

resp, err := client.Do(request)
if err != nil {
return redactURL(err)
Expand Down
Loading