Skip to content

Commit 073cf83

Browse files
committed
Update ociregistry and deal with the minor breaking changes
This also updates our `replace` to my new upstream fix that deals with `HEAD` on a Docker Hub digest failing when it shouldn't.
1 parent 05d9b2e commit 073cf83

File tree

4 files changed

+37
-31
lines changed

4 files changed

+37
-31
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ require (
2020
google.golang.org/protobuf v1.28.1 // indirect
2121
)
2222

23-
// https://github.com/cue-labs/oci/pull/27
24-
replace cuelabs.dev/go/oci/ociregistry => github.com/tianon/cuelabs-oci/ociregistry v0.0.0-20240216044210-8aa0c990bd77
23+
// https://github.com/cue-labs/oci/pull/29
24+
replace cuelabs.dev/go/oci/ociregistry => github.com/tianon/cuelabs-oci/ociregistry v0.0.0-20240322151419-7d3242933116

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
3232
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3333
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
3434
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
35-
github.com/tianon/cuelabs-oci/ociregistry v0.0.0-20240216044210-8aa0c990bd77 h1:9EPZm+sGlYHo6LleMXWR6s3P8SJEYA7/aovpJ76JSpw=
36-
github.com/tianon/cuelabs-oci/ociregistry v0.0.0-20240216044210-8aa0c990bd77/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24=
35+
github.com/tianon/cuelabs-oci/ociregistry v0.0.0-20240322151419-7d3242933116 h1:ZDy4uRAhzODJXRo4EoNpJTCiSeOs8wwrkfMJy3JyDps=
36+
github.com/tianon/cuelabs-oci/ociregistry v0.0.0-20240322151419-7d3242933116/go.mod h1:pK23AUVXuNzzTpfMCA06sxZGeVQ/75FdVtW249de9Uo=
3737
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
3838
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
3939
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

registry/client.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,24 @@ func Client(host string, opts *ociclient.Options) (ociregistry.Interface, error)
2525
if opts != nil {
2626
clientOptions = *opts
2727
}
28-
if clientOptions.HTTPClient == nil {
29-
clientOptions.HTTPClient = http.DefaultClient
28+
if clientOptions.Transport == nil {
29+
clientOptions.Transport = http.DefaultTransport
3030
}
3131

3232
// if we have a rate limiter configured for this registry, shim it in
3333
if limiter, ok := registryRateLimiters[host]; ok {
34-
clientOptions.HTTPClient = &rateLimitedRetryingDoer{
35-
doer: clientOptions.HTTPClient,
36-
limiter: limiter,
34+
clientOptions.Transport = &rateLimitedRetryingRoundTripper{
35+
roundTripper: clientOptions.Transport,
36+
limiter: limiter,
3737
}
3838
}
3939

40+
// install the "authorization" wrapper/shim
41+
clientOptions.Transport = ociauth.NewStdTransport(ociauth.StdTransportParams{
42+
Config: authConfig,
43+
Transport: clientOptions.Transport,
44+
})
45+
4046
connectHost := host
4147
if host == dockerHubCanonical {
4248
connectHost = dockerHubConnect
@@ -46,14 +52,6 @@ func Client(host string, opts *ociclient.Options) (ociregistry.Interface, error)
4652
// TODO some way for callers to specify that their "localhost" *does* require TLS (maybe only do this if `opts == nil`, but then users cannot supply *any* options and still get help setting Insecure for localhost 🤔 -- at least this is a more narrow use case than the opposite of not having a way to have non-localhost insecure registries)
4753
}
4854

49-
if clientOptions.Authorizer == nil {
50-
// TODO https://github.com/cue-labs/oci/pull/28 -- ideally we'd set this sooner, but https://github.com/cue-labs/oci/blob/5ebe80b0a9a67ae83802d1fb1a189a8f0d089fb0/ociregistry/ociclient/client.go#L278-L282 means we have to do it late in case we installed a rate limiting HTTPClient (or the caller provided a custom one)
51-
clientOptions.Authorizer = ociauth.NewStdAuthorizer(ociauth.StdAuthorizerParams{
52-
Config: authConfig,
53-
HTTPClient: clientOptions.HTTPClient,
54-
})
55-
}
56-
5755
hostOptions := clientOptions // make a copy, since "ociclient.New" mutates it (such that sharing the object afterwards probably isn't the best idea -- they'll have the same DebugID if so, which isn't ideal)
5856
client, err := ociclient.New(connectHost, &hostOptions)
5957
if err != nil {
@@ -86,7 +84,7 @@ func Client(host string, opts *ociclient.Options) (ociregistry.Interface, error)
8684
default:
8785
return nil, fmt.Errorf("unsupported DOCKERHUB_PUBLIC_PROXY (with path)")
8886
}
89-
// TODO complain about other URL bits (unsupported by "ociclient" except via custom "HTTPClient" / "HTTPDoer")
87+
// TODO complain about other URL bits (unsupported by "ociclient" except via custom "RoundTripper")
9088
} else if proxy := os.Getenv("DOCKERHUB_PUBLIC_PROXY_HOST"); proxy != "" {
9189
proxyHost = proxy
9290
}

registry/rate-limits.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"net/http"
55
"time"
66

7-
"cuelabs.dev/go/oci/ociregistry/ociclient"
87
"golang.org/x/time/rate"
98
)
109

@@ -14,13 +13,13 @@ var (
1413
}
1514
)
1615

17-
// an implementation of [ociclient.HTTPDoer] that transparently adds a total requests rate limit and 429-retrying behavior
18-
type rateLimitedRetryingDoer struct {
19-
doer ociclient.HTTPDoer
20-
limiter *rate.Limiter
16+
// an implementation of [net/http.RoundTripper] that transparently adds a total requests rate limit and 429-retrying behavior
17+
type rateLimitedRetryingRoundTripper struct {
18+
roundTripper http.RoundTripper
19+
limiter *rate.Limiter
2120
}
2221

23-
func (d *rateLimitedRetryingDoer) Do(req *http.Request) (*http.Response, error) {
22+
func (d *rateLimitedRetryingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
2423
requestRetryLimiter := rate.NewLimiter(rate.Every(time.Second), 1) // cap request retries at once per second
2524
firstTry := true
2625
ctx := req.Context()
@@ -32,23 +31,32 @@ func (d *rateLimitedRetryingDoer) Do(req *http.Request) (*http.Response, error)
3231
return nil, err
3332
}
3433

35-
if !firstTry && req.GetBody != nil {
36-
var err error
37-
req.Body, err = req.GetBody()
38-
if err != nil {
39-
return nil, err
34+
if !firstTry {
35+
// https://pkg.go.dev/net/http#RoundTripper
36+
// "RoundTrip should not modify the request, except for consuming and closing the Request's Body."
37+
if req.Body != nil {
38+
req.Body.Close()
39+
}
40+
req = req.Clone(ctx)
41+
if req.GetBody != nil {
42+
var err error
43+
req.Body, err = req.GetBody()
44+
if err != nil {
45+
return nil, err
46+
}
4047
}
4148
}
4249
firstTry = false
4350

44-
res, err := d.doer.Do(req)
51+
// in theory, this RoundTripper we're invoking should close req.Body (per the RoundTripper contract), so we shouldn't have to 🤞
52+
res, err := d.roundTripper.RoundTrip(req)
4553
if err != nil {
4654
return nil, err
4755
}
4856

4957
// TODO 503 should probably result in at least one or two auto-retries (especially with the automatic retry delay this injects)
5058
if res.StatusCode == 429 {
51-
// satisfy the big scary warning on https://pkg.go.dev/net/http#Client.Do about the downsides of failing to Close the response body
59+
// satisfy the big scary warnings on https://pkg.go.dev/net/http#RoundTripper and https://pkg.go.dev/net/http#Client.Do about the downsides of failing to Close the response body
5260
if err := res.Body.Close(); err != nil {
5361
return nil, err
5462
}

0 commit comments

Comments
 (0)