Skip to content

Commit b29bc95

Browse files
committed
Switch to avast/retry-go for HTTP retry
The hashicorp dependencies are MPL licensed and therefore not allowed in the CNCF. This means we now use the `avast/retry-go` implementation to achieve the same goal. Signed-off-by: Sascha Grunert <[email protected]>
1 parent b0e9f60 commit b29bc95

File tree

5 files changed

+58
-56
lines changed

5 files changed

+58
-56
lines changed

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,11 @@ require (
5656
cloud.google.com/go/pubsub v1.45.3
5757
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d
5858
github.com/DATA-DOG/go-sqlmock v1.5.2
59+
github.com/avast/retry-go/v4 v4.6.0
5960
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7
6061
github.com/go-redis/redismock/v9 v9.2.0
6162
github.com/go-sql-driver/mysql v1.8.1
6263
github.com/golang/mock v1.6.0
63-
github.com/hashicorp/go-cleanhttp v0.5.2
64-
github.com/hashicorp/go-retryablehttp v0.7.7
6564
github.com/jmoiron/sqlx v1.4.0
6665
github.com/redis/go-redis/v9 v9.7.0
6766
github.com/sassoftware/relic/v7 v7.6.2
@@ -132,7 +131,9 @@ require (
132131
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
133132
github.com/google/s2a-go v0.1.9 // indirect
134133
github.com/hashicorp/errwrap v1.1.0 // indirect
134+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
135135
github.com/hashicorp/go-multierror v1.1.1 // indirect
136+
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
136137
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
137138
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
138139
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPp
6464
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
6565
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
6666
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
67+
github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
68+
github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
6769
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
6870
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
6971
github.com/aws/aws-sdk-go-v2 v1.32.8 h1:cZV+NUS/eGxKXMtmyhtYPJ7Z4YLoI/V8bkTdRZfYhGo=

pkg/client/options.go

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
package client
1616

1717
import (
18+
"fmt"
1819
"net/http"
1920
"time"
2021

21-
"github.com/hashicorp/go-retryablehttp"
22+
"github.com/avast/retry-go/v4"
2223
)
2324

2425
// Option is a functional option for customizing static signatures.
@@ -30,7 +31,6 @@ type options struct {
3031
RetryWaitMin time.Duration
3132
RetryWaitMax time.Duration
3233
InsecureTLS bool
33-
Logger interface{}
3434
NoDisableKeepalives bool
3535
Headers map[string][]string
3636
}
@@ -81,14 +81,9 @@ func WithRetryWaitMax(t time.Duration) Option {
8181
}
8282
}
8383

84-
// WithLogger sets the logger; it must implement either retryablehttp.Logger or retryablehttp.LeveledLogger; if not, this will not take effect.
84+
// Deprecated: WithLogger sets the logger; this will have no effect and be removed in future versions.
8585
func WithLogger(logger interface{}) Option {
86-
return func(o *options) {
87-
switch logger.(type) {
88-
case retryablehttp.Logger, retryablehttp.LeveledLogger:
89-
o.Logger = logger
90-
}
91-
}
86+
return func(o *options) {}
9287
}
9388

9489
// WithInsecureTLS disables TLS verification.
@@ -113,33 +108,43 @@ func WithHeaders(h map[string][]string) Option {
113108
}
114109

115110
type roundTripper struct {
116-
http.RoundTripper
117-
UserAgent string
118-
Headers map[string][]string
111+
inner http.RoundTripper
112+
*options
119113
}
120114

121115
// RoundTrip implements `http.RoundTripper`
122-
func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
123-
req.Header.Set("User-Agent", rt.UserAgent)
124-
for k, v := range rt.Headers {
116+
func (rt *roundTripper) RoundTrip(req *http.Request) (res *http.Response, err error) {
117+
req.Header.Set("User-Agent", rt.options.UserAgent)
118+
for k, v := range rt.options.Headers {
125119
for _, h := range v {
126120
req.Header.Add(k, h)
127121
}
128122
}
129-
return rt.RoundTripper.RoundTrip(req)
123+
124+
err = retry.Do(func() (err error) {
125+
res, err = rt.inner.RoundTrip(req)
126+
if err != nil {
127+
return err
128+
}
129+
if res.StatusCode != 200 {
130+
return fmt.Errorf("%d: %s", res.StatusCode, res.Status)
131+
}
132+
return nil
133+
},
134+
retry.Attempts(rt.options.RetryCount),
135+
retry.Delay(rt.options.RetryWaitMin),
136+
retry.MaxDelay(rt.options.RetryWaitMax),
137+
)
138+
139+
return res, err
130140
}
131141

132-
func createRoundTripper(inner http.RoundTripper, o *options) http.RoundTripper {
142+
func wrapRoundTripper(inner http.RoundTripper, o *options) http.RoundTripper {
133143
if inner == nil {
134144
inner = http.DefaultTransport
135145
}
136-
if o.UserAgent == "" && o.Headers == nil {
137-
// There's nothing to do...
138-
return inner
139-
}
140146
return &roundTripper{
141-
RoundTripper: inner,
142-
UserAgent: o.UserAgent,
143-
Headers: o.Headers,
147+
inner: inner,
148+
options: o,
144149
}
145150
}

pkg/client/options_test.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,12 @@ package client
1717
import (
1818
"log"
1919
"net/http"
20-
"os"
2120
"testing"
2221

2322
"github.com/google/go-cmp/cmp"
2423
)
2524

2625
func TestMakeOptions(t *testing.T) {
27-
customLogger := log.New(os.Stdout, "", log.LstdFlags)
28-
2926
tests := []struct {
3027
desc string
3128

@@ -42,10 +39,6 @@ func TestMakeOptions(t *testing.T) {
4239
desc: "WithRetryCount",
4340
opts: []Option{WithRetryCount(2)},
4441
want: &options{UserAgent: "", RetryCount: 2},
45-
}, {
46-
desc: "WithLogger",
47-
opts: []Option{WithLogger(customLogger)},
48-
want: &options{UserAgent: "", RetryCount: DefaultRetryCount, Logger: customLogger},
4942
}, {
5043
desc: "WithLoggerNil",
5144
opts: []Option{WithLogger(nil)},
@@ -82,11 +75,11 @@ func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
8275
return m.resp, m.err
8376
}
8477

85-
func TestCreateRoundTripper(t *testing.T) {
78+
func TestWrapRoundTripper(t *testing.T) {
8679
t.Run("always returns non-nil", func(t *testing.T) {
87-
got := createRoundTripper(nil, &options{})
80+
got := wrapRoundTripper(nil, &options{})
8881
if got == nil {
89-
t.Errorf("createRoundTripper() should never return a nil `http.RoundTripper`")
82+
t.Errorf("wrapRoundTripper() should never return a nil `http.RoundTripper`")
9083
}
9184
})
9285

@@ -104,7 +97,7 @@ func TestCreateRoundTripper(t *testing.T) {
10497
expectedUserAgent := "test UserAgent"
10598

10699
m := &mockRoundTripper{}
107-
rt := createRoundTripper(m, &options{
100+
rt := wrapRoundTripper(m, &options{
108101
UserAgent: expectedUserAgent,
109102
})
110103
m.resp = testResp

pkg/client/rekor_client.go

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ package client
1616

1717
import (
1818
"crypto/tls"
19+
"net"
1920
"net/http"
2021
"net/url"
22+
"time"
2123

2224
"github.com/go-openapi/runtime"
2325
httptransport "github.com/go-openapi/runtime/client"
2426
"github.com/go-openapi/strfmt"
2527

26-
"github.com/hashicorp/go-cleanhttp"
27-
retryablehttp "github.com/hashicorp/go-retryablehttp"
2828
"github.com/sigstore/rekor/pkg/generated/client"
2929
"github.com/sigstore/rekor/pkg/util"
3030
)
@@ -36,25 +36,26 @@ func GetRekorClient(rekorServerURL string, opts ...Option) (*client.Rekor, error
3636
}
3737
o := makeOptions(opts...)
3838

39-
retryableClient := retryablehttp.NewClient()
40-
defaultTransport := cleanhttp.DefaultTransport()
41-
if o.NoDisableKeepalives {
42-
defaultTransport.DisableKeepAlives = false
39+
transport := &http.Transport{
40+
Proxy: http.ProxyFromEnvironment,
41+
DialContext: (&net.Dialer{
42+
Timeout: 30 * time.Second,
43+
KeepAlive: 30 * time.Second,
44+
DualStack: true,
45+
}).DialContext,
46+
MaxIdleConns: 100,
47+
IdleConnTimeout: 90 * time.Second,
48+
TLSHandshakeTimeout: 10 * time.Second,
49+
ExpectContinueTimeout: 1 * time.Second,
50+
ForceAttemptHTTP2: true,
51+
MaxIdleConnsPerHost: -1,
52+
DisableKeepAlives: !o.NoDisableKeepalives,
53+
TLSClientConfig: &tls.Config{InsecureSkipVerify: o.InsecureTLS},
4354
}
44-
if o.InsecureTLS {
45-
/* #nosec G402 */
46-
defaultTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
47-
}
48-
retryableClient.HTTPClient = &http.Client{
49-
Transport: defaultTransport,
50-
}
51-
retryableClient.RetryMax = int(o.RetryCount)
52-
retryableClient.RetryWaitMin = o.RetryWaitMin
53-
retryableClient.RetryWaitMax = o.RetryWaitMax
54-
retryableClient.Logger = o.Logger
5555

56-
httpClient := retryableClient.StandardClient()
57-
httpClient.Transport = createRoundTripper(httpClient.Transport, o)
56+
httpClient := &http.Client{
57+
Transport: wrapRoundTripper(transport, o),
58+
}
5859

5960
// sanitize path
6061
if url.Path == "" {

0 commit comments

Comments
 (0)