Skip to content

Commit 22640fa

Browse files
committed
[image-builder] Use req.GetUseRetryClient() instead of feature flag resolved on startup
1 parent 8853bed commit 22640fa

File tree

4 files changed

+52
-44
lines changed

4 files changed

+52
-44
lines changed

components/image-builder-mk3/cmd/run.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"time"
1010

1111
"github.com/gitpod-io/gitpod/common-go/baseserver"
12-
"github.com/gitpod-io/gitpod/common-go/experiments"
1312

1413
"github.com/gitpod-io/gitpod/common-go/log"
1514
"github.com/gitpod-io/gitpod/image-builder/api"
@@ -41,12 +40,7 @@ var runCmd = &cobra.Command{
4140
span, ctx := opentracing.StartSpanFromContext(ctx, "/cmd/Run")
4241
defer span.Finish()
4342

44-
// Check feature flag for retry client
45-
experimentsClient := experiments.NewClient()
46-
useRetryClient := experimentsClient.GetBoolValue(ctx, "imagebuilder_retry_resolve", false, experiments.Attributes{})
47-
log.WithField("useRetryClient", useRetryClient).Info("Feature flag imagebuilder_retry_resolve checked")
48-
49-
service, err := orchestrator.NewOrchestratingBuilder(cfg.Orchestrator, useRetryClient)
43+
service, err := orchestrator.NewOrchestratingBuilder(cfg.Orchestrator)
5044
if err != nil {
5145
log.Fatal(err)
5246
}

components/image-builder-mk3/pkg/orchestrator/orchestrator.go

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"errors"
1212
"fmt"
1313
"io"
14+
"net/http"
1415
"os"
1516
"path/filepath"
1617
"sort"
@@ -56,7 +57,7 @@ const (
5657
)
5758

5859
// NewOrchestratingBuilder creates a new orchestrating image builder
59-
func NewOrchestratingBuilder(cfg config.Configuration, useRetryClient bool) (res *Orchestrator, err error) {
60+
func NewOrchestratingBuilder(cfg config.Configuration) (res *Orchestrator, err error) {
6061
var authentication auth.CompositeAuth
6162
if cfg.PullSecretFile != "" {
6263
fn := cfg.PullSecretFile
@@ -106,17 +107,7 @@ func NewOrchestratingBuilder(cfg config.Configuration, useRetryClient bool) (res
106107
wsman = wsmanapi.NewWorkspaceManagerClient(conn)
107108
}
108109

109-
// Create RefResolver with conditional retry client based on feature flag
110-
var refResolver resolve.DockerRefResolver
111-
if useRetryClient {
112-
refResolver = &resolve.StandaloneRefResolver{
113-
Client: NewRetryTimeoutClient(),
114-
}
115-
log.Info("Using retry timeout client for Docker registry requests")
116-
} else {
117-
refResolver = &resolve.StandaloneRefResolver{}
118-
log.Info("Using standard client for Docker registry requests")
119-
}
110+
retryResolveClient := NewRetryTimeoutClient()
120111

121112
o := &Orchestrator{
122113
Config: cfg,
@@ -125,7 +116,9 @@ func NewOrchestratingBuilder(cfg config.Configuration, useRetryClient bool) (res
125116
BaseImageRepository: cfg.BaseImageRepository,
126117
WorkspaceImageRepository: cfg.WorkspaceImageRepository,
127118
},
128-
RefResolver: refResolver,
119+
RefResolver: &resolve.StandaloneRefResolver{},
120+
121+
retryResolveClient: retryResolveClient,
129122

130123
wsman: wsman,
131124
buildListener: make(map[string]map[buildListener]struct{}),
@@ -145,6 +138,8 @@ type Orchestrator struct {
145138
AuthResolver auth.Resolver
146139
RefResolver resolve.DockerRefResolver
147140

141+
retryResolveClient *http.Client
142+
148143
wsman wsmanapi.WorkspaceManagerClient
149144

150145
buildListener map[string]map[buildListener]struct{}
@@ -173,7 +168,7 @@ func (o *Orchestrator) ResolveBaseImage(ctx context.Context, req *protocol.Resol
173168

174169
reqauth := o.AuthResolver.ResolveRequestAuth(ctx, req.Auth)
175170

176-
refstr, err := o.getAbsoluteImageRef(ctx, req.Ref, reqauth)
171+
refstr, err := o.getAbsoluteImageRef(ctx, req.Ref, reqauth, req.GetUseRetryClient())
177172
if err != nil {
178173
return nil, err
179174
}
@@ -190,7 +185,8 @@ func (o *Orchestrator) ResolveWorkspaceImage(ctx context.Context, req *protocol.
190185
tracing.LogRequestSafe(span, req)
191186

192187
reqauth := o.AuthResolver.ResolveRequestAuth(ctx, req.Auth)
193-
baseref, err := o.getBaseImageRef(ctx, req.Source, reqauth)
188+
useRetryClient := req.GetUseRetryClient()
189+
baseref, err := o.getBaseImageRef(ctx, req.Source, reqauth, useRetryClient)
194190
if _, ok := status.FromError(err); err != nil && ok {
195191
return nil, err
196192
}
@@ -209,7 +205,7 @@ func (o *Orchestrator) ResolveWorkspaceImage(ctx context.Context, req *protocol.
209205
if err != nil {
210206
return nil, status.Errorf(codes.Internal, "cannot get workspace image authentication: %v", err)
211207
}
212-
exists, err := o.checkImageExists(ctx, refstr, auth)
208+
exists, err := o.checkImageExists(ctx, refstr, auth, useRetryClient)
213209
if err != nil {
214210
return nil, status.Errorf(codes.Internal, "cannot resolve workspace image: %s", err.Error())
215211
}
@@ -240,8 +236,8 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
240236

241237
// resolve build request authentication
242238
reqauth := o.AuthResolver.ResolveRequestAuth(ctx, req.Auth)
243-
244-
log.WithField("forceRebuild", req.GetForceRebuild()).WithField("baseImageNameResolved", req.BaseImageNameResolved).Info("build request")
239+
useRetryClient := req.GetUseRetryClient()
240+
log.WithField("forceRebuild", req.GetForceRebuild()).WithField("baseImageNameResolved", req.BaseImageNameResolved).WithField("useRetryClient", useRetryClient).Info("build request")
245241

246242
// resolve to ref to baseImageNameResolved (if it exists)
247243
if req.BaseImageNameResolved != "" && !req.GetForceRebuild() {
@@ -261,7 +257,7 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
261257
}
262258

263259
// check if needs build -> early return
264-
exists, err := o.checkImageExists(ctx, wsrefstr, wsrefAuth)
260+
exists, err := o.checkImageExists(ctx, wsrefstr, wsrefAuth, useRetryClient)
265261
if err != nil {
266262
return status.Errorf(codes.Internal, "cannot check if image is already built: %q", err)
267263
}
@@ -276,7 +272,7 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
276272
}
277273
return nil
278274
}
279-
baseref, err := o.getAbsoluteImageRef(ctx, req.BaseImageNameResolved, reqauth)
275+
baseref, err := o.getAbsoluteImageRef(ctx, req.BaseImageNameResolved, reqauth, useRetryClient)
280276
if err == nil {
281277
req.Source.From = &protocol.BuildSource_Ref{
282278
Ref: &protocol.BuildSourceReference{
@@ -287,7 +283,7 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
287283
}
288284

289285
log.Info("falling through to old way of building")
290-
baseref, err := o.getBaseImageRef(ctx, req.Source, reqauth)
286+
baseref, err := o.getBaseImageRef(ctx, req.Source, reqauth, useRetryClient)
291287
if _, ok := status.FromError(err); err != nil && ok {
292288
log.WithError(err).Error("gRPC status error")
293289
return err
@@ -307,7 +303,7 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
307303
}
308304

309305
// check if needs build -> early return
310-
exists, err := o.checkImageExists(ctx, wsrefstr, wsrefAuth)
306+
exists, err := o.checkImageExists(ctx, wsrefstr, wsrefAuth, req.GetUseRetryClient())
311307
if err != nil {
312308
return status.Errorf(codes.Internal, "cannot check if image is already built: %q", err)
313309
}
@@ -476,7 +472,7 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
476472
// "cannot pull from reg.gitpod.io" error message. Instead the image-build should fail properly.
477473
// To do this, we resolve the built image afterwards to ensure it was actually built.
478474
if update.Status == protocol.BuildStatus_done_success {
479-
exists, err := o.checkImageExists(ctx, wsrefstr, wsrefAuth)
475+
exists, err := o.checkImageExists(ctx, wsrefstr, wsrefAuth, useRetryClient)
480476
if err != nil {
481477
update.Status = protocol.BuildStatus_done_failure
482478
update.Message = fmt.Sprintf("cannot check if workspace image exists after the build: %v", err)
@@ -593,12 +589,12 @@ func (o *Orchestrator) ListBuilds(ctx context.Context, req *protocol.ListBuildsR
593589
return &protocol.ListBuildsResponse{Builds: res}, nil
594590
}
595591

596-
func (o *Orchestrator) checkImageExists(ctx context.Context, ref string, authentication *auth.Authentication) (exists bool, err error) {
592+
func (o *Orchestrator) checkImageExists(ctx context.Context, ref string, authentication *auth.Authentication, useRetryClient bool) (exists bool, err error) {
597593
span, ctx := opentracing.StartSpanFromContext(ctx, "checkImageExists")
598594
defer tracing.FinishSpan(span, &err)
599595
span.SetTag("ref", ref)
600596

601-
_, err = o.RefResolver.Resolve(ctx, ref, resolve.WithAuthentication(authentication))
597+
_, err = o.RefResolver.Resolve(ctx, ref, resolve.WithAuthentication(authentication), o.withRetryIfEnabled(useRetryClient))
602598
if errors.Is(err, resolve.ErrNotFound) {
603599
return false, nil
604600
}
@@ -613,18 +609,19 @@ func (o *Orchestrator) checkImageExists(ctx context.Context, ref string, authent
613609
}
614610

615611
// getAbsoluteImageRef returns the "digest" form of an image, i.e. contains no mutable image tags
616-
func (o *Orchestrator) getAbsoluteImageRef(ctx context.Context, ref string, allowedAuth auth.AllowedAuthFor) (res string, err error) {
617-
span, ctx := opentracing.StartSpanFromContext(ctx, "getAbsoluteImageRef")
612+
func (o *Orchestrator) getAbsoluteImageRef(ctx context.Context, ref string, allowedAuth auth.AllowedAuthFor, useRetryClient bool) (res string, err error) {
613+
span, ctx := opentracing.StartSpanFromContext(ctx, "getAbsoluteImageRefWithResolver")
618614
defer tracing.FinishSpan(span, &err)
619615
span.LogKV("ref", ref)
616+
span.LogKV("useRetryClient", useRetryClient)
620617

621-
log.WithField("ref", ref).Debug("getAbsoluteImageRef")
618+
log.WithField("ref", ref).WithField("useRetryClient", useRetryClient).Debug("getAbsoluteImageRefWithResolver")
622619
auth, err := allowedAuth.GetAuthFor(ctx, o.Auth, ref)
623620
if err != nil {
624621
return "", status.Errorf(codes.InvalidArgument, "cannt resolve base image ref: %v", err)
625622
}
626623

627-
ref, err = o.RefResolver.Resolve(ctx, ref, resolve.WithAuthentication(auth))
624+
ref, err = o.RefResolver.Resolve(ctx, ref, resolve.WithAuthentication(auth), o.withRetryIfEnabled(useRetryClient))
628625
if errors.Is(err, resolve.ErrNotFound) {
629626
return "", status.Error(codes.NotFound, "cannot resolve image")
630627
}
@@ -645,13 +642,20 @@ func (o *Orchestrator) getAbsoluteImageRef(ctx context.Context, ref string, allo
645642
return ref, nil
646643
}
647644

648-
func (o *Orchestrator) getBaseImageRef(ctx context.Context, bs *protocol.BuildSource, allowedAuth auth.AllowedAuthFor) (res string, err error) {
645+
func (o *Orchestrator) withRetryIfEnabled(useRetryClient bool) resolve.DockerRefResolverOption {
646+
if useRetryClient {
647+
return resolve.WithHttpClient(o.retryResolveClient)
648+
}
649+
return resolve.WithHttpClient(nil)
650+
}
651+
652+
func (o *Orchestrator) getBaseImageRef(ctx context.Context, bs *protocol.BuildSource, allowedAuth auth.AllowedAuthFor, useRetryClient bool) (res string, err error) {
649653
span, ctx := opentracing.StartSpanFromContext(ctx, "getBaseImageRef")
650654
defer tracing.FinishSpan(span, &err)
651655

652656
switch src := bs.From.(type) {
653657
case *protocol.BuildSource_Ref:
654-
return o.getAbsoluteImageRef(ctx, src.Ref.Ref, allowedAuth)
658+
return o.getAbsoluteImageRef(ctx, src.Ref.Ref, allowedAuth, useRetryClient)
655659

656660
case *protocol.BuildSource_File:
657661
manifest := map[string]string{

components/image-builder-mk3/pkg/orchestrator/orchestrator_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func TestBuild(t *testing.T) {
138138
BaseImageRepository: "registry/base",
139139
WorkspaceImageRepository: "registry/workspace",
140140
BuilderImage: "builder-image",
141-
}, false)
141+
})
142142
if err != nil {
143143
t.Fatal(err)
144144
}
@@ -188,7 +188,7 @@ func TestResolveBaseImage(t *testing.T) {
188188
WorkspaceManager: config.WorkspaceManagerConfig{
189189
Client: wsmock.NewMockWorkspaceManagerClient(ctrl),
190190
},
191-
}, false)
191+
})
192192
if err != nil {
193193
t.Fatal(err)
194194
}

components/image-builder-mk3/pkg/resolve/resolve.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ var (
4646
// StandaloneRefResolver can resolve image references without a Docker daemon
4747
type StandaloneRefResolver struct {
4848
ResolverFactory func() remotes.Resolver
49-
Client *http.Client
5049
}
5150

5251
// Resolve resolves a mutable Docker tag to its absolute digest form by asking the corresponding Docker registry
@@ -74,8 +73,8 @@ func (sr *StandaloneRefResolver) Resolve(ctx context.Context, ref string, opts .
7473
}))),
7574
}
7675

77-
if sr.Client != nil {
78-
registryOpts = append(registryOpts, dockerremote.WithClient(sr.Client))
76+
if options.Client != nil {
77+
registryOpts = append(registryOpts, dockerremote.WithClient(options.Client))
7978
}
8079

8180
r = dockerremote.NewResolver(dockerremote.ResolverOptions{
@@ -164,7 +163,8 @@ func (sr *StandaloneRefResolver) Resolve(ctx context.Context, ref string, opts .
164163
}
165164

166165
type opts struct {
167-
Auth *auth.Authentication
166+
Auth *auth.Authentication
167+
Client *http.Client
168168
}
169169

170170
// DockerRefResolverOption configures reference resolution
@@ -181,6 +181,16 @@ func WithAuthentication(auth *auth.Authentication) DockerRefResolverOption {
181181
}
182182
}
183183

184+
// WithHttpClient sets the HTTP client to use for making requests to the Docker registry.
185+
func WithHttpClient(client *http.Client) DockerRefResolverOption {
186+
return func(o *opts) {
187+
if client == nil {
188+
log.Debug("WithHttpClient - client was nil")
189+
}
190+
o.Client = client
191+
}
192+
}
193+
184194
func getOptions(o []DockerRefResolverOption) *opts {
185195
var res opts
186196
for _, opt := range o {

0 commit comments

Comments
 (0)