File: client_options.go

package info (click to toggle)
gitlab-agent 16.11.5-1
  • links: PTS, VCS
  • area: contrib
  • in suites: experimental
  • size: 7,072 kB
  • sloc: makefile: 193; sh: 55; ruby: 3
file content (162 lines) | stat: -rw-r--r-- 5,025 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package gitlab

import (
	"context"
	"crypto/tls"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/hashicorp/go-retryablehttp"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v16/internal/tool/httpz"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v16/internal/tool/tlstool"
	"go.opentelemetry.io/otel"
	otelmetric "go.opentelemetry.io/otel/metric"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/trace"
)

const (
	// Default retry configuration
	defaultRetryWaitMin = 100 * time.Millisecond
	defaultRetryWaitMax = 30 * time.Second
	defaultRetryMax     = 4
)

type RetryConfig struct {
	// Logger instance. Can be either retryablehttp.Logger or retryablehttp.LeveledLogger
	Logger interface{}

	RetryWaitMin time.Duration // Minimum time to wait
	RetryWaitMax time.Duration // Maximum time to wait
	RetryMax     int           // Maximum number of retries

	// RequestLogHook allows a user-supplied function to be called
	// before each retry.
	RequestLogHook retryablehttp.RequestLogHook

	// ResponseLogHook allows a user-supplied function to be called
	// with the response from each HTTP request executed.
	ResponseLogHook retryablehttp.ResponseLogHook

	// CheckRetry specifies the policy for handling retries, and is called
	// after each request. The default policy is retryablehttp.DefaultRetryPolicy.
	CheckRetry retryablehttp.CheckRetry

	// Backoff specifies the policy for how long to wait between retries.
	// retryablehttp.DefaultBackoff is used by default.
	Backoff retryablehttp.Backoff
}

type transportConfig struct {
	Proxy                 func(*http.Request) (*url.URL, error)
	DialContext           func(ctx context.Context, network, address string) (net.Conn, error)
	TLSClientConfig       *tls.Config
	TLSHandshakeTimeout   time.Duration
	MaxIdleConns          int
	MaxIdleConnsPerHost   int
	MaxConnsPerHost       int
	IdleConnTimeout       time.Duration
	ResponseHeaderTimeout time.Duration
	ForceAttemptHTTP2     bool
}

// clientConfig holds configuration for the client.
type clientConfig struct {
	retryConfig     RetryConfig
	transportConfig transportConfig
	tracePropagator propagation.TextMapPropagator
	traceProvider   trace.TracerProvider
	meterProvider   otelmetric.MeterProvider
	limiter         httpz.Limiter
	userAgent       string
}

// ClientOption to configure the client.
type ClientOption func(*clientConfig)

func applyClientOptions(opts []ClientOption) clientConfig {
	dialer := &net.Dialer{
		Timeout: 30 * time.Second,
	}
	config := clientConfig{
		retryConfig: RetryConfig{
			RetryWaitMin: defaultRetryWaitMin,
			RetryWaitMax: defaultRetryWaitMax,
			RetryMax:     defaultRetryMax,
			CheckRetry:   retryablehttp.DefaultRetryPolicy,
			Backoff:      retryablehttp.DefaultBackoff,
		},
		transportConfig: transportConfig{
			Proxy:                 http.ProxyFromEnvironment,
			DialContext:           dialer.DialContext,
			TLSClientConfig:       tlstool.DefaultClientTLSConfig(),
			TLSHandshakeTimeout:   10 * time.Second,
			MaxIdleConns:          100,
			MaxIdleConnsPerHost:   50,
			MaxConnsPerHost:       50,
			IdleConnTimeout:       90 * time.Second,
			ResponseHeaderTimeout: 20 * time.Second,
			ForceAttemptHTTP2:     true,
		},
		tracePropagator: otel.GetTextMapPropagator(),
		traceProvider:   otel.GetTracerProvider(),
		meterProvider:   otel.GetMeterProvider(),
		userAgent:       "",
	}
	for _, v := range opts {
		v(&config)
	}

	return config
}

// WithRetryConfig configures retry behavior.
func WithRetryConfig(retryConfig RetryConfig) ClientOption {
	return func(config *clientConfig) {
		config.retryConfig = retryConfig
	}
}

// WithTextMapPropagator sets a custom trace propagator to be used, otherwise the OTEL's global TextMapPropagator is used.
func WithTextMapPropagator(p propagation.TextMapPropagator) ClientOption {
	return func(config *clientConfig) {
		config.tracePropagator = p
	}
}

// WithTracerProvider sets a custom trace provider to be used, otherwise the OTEL's global TracerProvider is used.
func WithTracerProvider(traceProvider trace.TracerProvider) ClientOption {
	return func(config *clientConfig) {
		config.traceProvider = traceProvider
	}
}

// WithMeterProvider sets a custom meter provider to be used, otherwise the OTEL's global MeterProvider is used.
func WithMeterProvider(meterProvider otelmetric.MeterProvider) ClientOption {
	return func(config *clientConfig) {
		config.meterProvider = meterProvider
	}
}

// WithUserAgent configures the User-Agent header on the http client.
func WithUserAgent(userAgent string) ClientOption {
	return func(config *clientConfig) {
		config.userAgent = userAgent
	}
}

// WithTLSConfig sets the TLS config to use.
func WithTLSConfig(tlsConfig *tls.Config) ClientOption {
	return func(config *clientConfig) {
		config.transportConfig.TLSClientConfig = tlsConfig
	}
}

// WithRateLimiter sets the rate limiter to use.
func WithRateLimiter(limiter httpz.Limiter) ClientOption {
	return func(config *clientConfig) {
		config.limiter = limiter
	}
}