Skip to content

Commit

Permalink
Fix issues in BuildImage() (testcontainers#2626)
Browse files Browse the repository at this point in the history
* Don't accumulate errors

The code already logs them so no need to return them all to the caller - the calling code will likely log them too. This will result in the same errors being logged twice. This is confusing for the user.

* RetryNotify -> RetryNotifyWithData

* Do not reuse buildOptions.Context

buildOptions.Context cannot be reused because it might have been partially consumed by the failed ImageBuild(). So, the next invocation will send a partial context, which will not work correctly.

* Always close the response body

* Always close the build context

This ensures all resources are released properly.
  • Loading branch information
ash2k authored Jul 5, 2024
1 parent 3f73722 commit 306f185
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 22 deletions.
14 changes: 8 additions & 6 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ func (c *ContainerRequest) Validate() error {
}

// GetContext retrieve the build context for the request
// Must be closed when no longer needed.
func (c *ContainerRequest) GetContext() (io.Reader, error) {
var includes []string = []string{"."}

Expand Down Expand Up @@ -356,12 +357,6 @@ func (c *ContainerRequest) BuildOptions() (types.ImageBuildOptions, error) {
buildOptions.BuildArgs = c.GetBuildArgs()
buildOptions.Dockerfile = c.GetDockerfile()

buildContext, err := c.GetContext()
if err != nil {
return buildOptions, err
}
buildOptions.Context = buildContext

// Make sure the auth configs from the Dockerfile are set right after the user-defined build options.
authsFromDockerfile := getAuthConfigsFromDockerfile(c)

Expand Down Expand Up @@ -400,6 +395,13 @@ func (c *ContainerRequest) BuildOptions() (types.ImageBuildOptions, error) {
buildOptions.Labels = core.DefaultLabels(core.SessionID())
}

// Do this as late as possible to ensure we don't leak the context on error/panic.
buildContext, err := c.GetContext()
if err != nil {
return buildOptions, err
}
buildOptions.Context = buildContext

return buildOptions, nil
}

Expand Down
38 changes: 22 additions & 16 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,35 +882,36 @@ var _ ContainerProvider = (*DockerProvider)(nil)

// BuildImage will build and image from context and Dockerfile, then return the tag
func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (string, error) {
buildOptions, err := img.BuildOptions()
if err != nil {
return "", err
}
var buildOptions types.ImageBuildOptions
resp, err := backoff.RetryNotifyWithData(
func() (types.ImageBuildResponse, error) {
var err error
buildOptions, err = img.BuildOptions()
if err != nil {
return types.ImageBuildResponse{}, backoff.Permanent(err)
}
defer tryClose(buildOptions.Context) // release resources in any case

var buildError error
var resp types.ImageBuildResponse
err = backoff.RetryNotify(
func() error {
resp, err = p.client.ImageBuild(ctx, buildOptions.Context, buildOptions)
resp, err := p.client.ImageBuild(ctx, buildOptions.Context, buildOptions)
if err != nil {
buildError = errors.Join(buildError, err)
if isPermanentClientError(err) {
return backoff.Permanent(err)
return types.ImageBuildResponse{}, backoff.Permanent(err)
}
return err
return types.ImageBuildResponse{}, err
}
defer p.Close()

return nil
return resp, nil
},
backoff.WithContext(backoff.NewExponentialBackOff(), ctx),
func(err error, duration time.Duration) {
p.Logger.Printf("Failed to build image: %s, will retry", err)
},
)
if err != nil {
return "", errors.Join(buildError, err)
return "", err
}
defer resp.Body.Close()

if img.ShouldPrintBuildLog() {
termFd, isTerm := term.GetFdInfo(os.Stderr)
Expand All @@ -927,8 +928,6 @@ func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (st
return "", err
}

_ = resp.Body.Close()

// the first tag is the one we want
return buildOptions.Tags[0], nil
}
Expand Down Expand Up @@ -1664,3 +1663,10 @@ func isPermanentClientError(err error) bool {
}
return false
}

func tryClose(r io.Reader) {
rc, ok := r.(io.Closer)
if ok {
_ = rc.Close()
}
}

0 comments on commit 306f185

Please sign in to comment.