Skip to content

Commit

Permalink
Modify fetcher
Browse files Browse the repository at this point in the history
When Docker Daemon is available, defer to Docker Daemon when pulling remote images.
The motivation is that the Docker Daemon already handles more edge cases that we do.

Signed-off-by: Anthony Emengo <[email protected]>
  • Loading branch information
Anthony Emengo committed Apr 27, 2021
1 parent 4d4f310 commit 74a3519
Showing 1 changed file with 36 additions and 28 deletions.
64 changes: 36 additions & 28 deletions internal/image/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"regexp"
"strings"

"github.com/buildpacks/imgutil/remote"

"github.com/buildpacks/imgutil"
"github.com/buildpacks/imgutil/local"
"github.com/buildpacks/imgutil/remote"
"github.com/buildpacks/lifecycle/auth"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
Expand Down Expand Up @@ -38,50 +41,52 @@ func NewFetcher(logger logging.Logger, docker client.CommonAPIClient) *Fetcher {
var ErrNotFound = errors.New("not found")

func (f *Fetcher) Fetch(ctx context.Context, name string, daemon bool, pullPolicy config.PullPolicy) (imgutil.Image, error) {
if daemon {
if pullPolicy == config.PullNever {
return f.fetchDaemonImage(name)
} else if pullPolicy == config.PullIfNotPresent {
img, err := f.fetchDaemonImage(name)
if err == nil || !errors.Is(err, ErrNotFound) {
return img, err
}
if !daemon {
return f.fetchRemoteImage(name)
}

switch pullPolicy {
case config.PullNever:
img, err := f.fetchDaemonImage(name)
return img, err
case config.PullIfNotPresent:
img, err := f.fetchDaemonImage(name)
if err == nil || !errors.Is(err, ErrNotFound) {
return img, err
}
}

image, err := remote.NewImage(name, authn.DefaultKeychain, remote.FromBaseImage(name))
if err != nil {
f.logger.Debugf("Pulling image %s", style.Symbol(name))
if err := f.pullImage(ctx, name); err != nil {
return nil, err
}

remoteFound := image.Found()
return f.fetchDaemonImage(name)
}

if daemon {
if remoteFound {
f.logger.Debugf("Pulling image %s", style.Symbol(name))
if err := f.pullImage(ctx, name); err != nil {
return nil, err
}
}
return f.fetchDaemonImage(name)
func (f *Fetcher) fetchDaemonImage(name string) (imgutil.Image, error) {
image, err := local.NewImage(name, f.docker, local.FromBaseImage(name))
if err != nil {
return nil, err
}

if !remoteFound {
return nil, errors.Wrapf(ErrNotFound, "image %s does not exist in registry", style.Symbol(name))
if !image.Found() {
return nil, errors.Wrapf(ErrNotFound, "image %s does not exist on the daemon", style.Symbol(name))
}

return image, nil
}

func (f *Fetcher) fetchDaemonImage(name string) (imgutil.Image, error) {
image, err := local.NewImage(name, f.docker, local.FromBaseImage(name))
func (f *Fetcher) fetchRemoteImage(name string) (imgutil.Image, error) {
image, err := remote.NewImage(name, authn.DefaultKeychain, remote.FromBaseImage(name))
if err != nil {
return nil, err
}

if !image.Found() {
return nil, errors.Wrapf(ErrNotFound, "image %s does not exist on the daemon", style.Symbol(name))
return nil, errors.Wrapf(ErrNotFound, "image %s does not exist in registry", style.Symbol(name))
}

return image, nil
}

Expand All @@ -90,10 +95,13 @@ func (f *Fetcher) pullImage(ctx context.Context, imageID string) error {
if err != nil {
return err
}
rc, err := f.docker.ImagePull(ctx, imageID, types.ImagePullOptions{
RegistryAuth: regAuth,
})

rc, err := f.docker.ImagePull(ctx, imageID, types.ImagePullOptions{RegistryAuth: regAuth})
if err != nil {
if ok, _ := regexp.MatchString(fmt.Sprintf(`manifest for %s.* not found: manifest unknown: manifest unknown`, imageID), err.Error()); ok {
return errors.Wrapf(ErrNotFound, "image %s does not exist on the daemon", style.Symbol(imageID))
}

return err
}

Expand Down

0 comments on commit 74a3519

Please sign in to comment.