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 <aemengo@vmware.com>
  • Loading branch information
Anthony Emengo committed Apr 27, 2021
1 parent 4d4f310 commit de26af4
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 32 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
15 changes: 11 additions & 4 deletions internal/image/fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,23 @@ func TestFetcher(t *testing.T) {

func testFetcher(t *testing.T, when spec.G, it spec.S) {
var (
fetcher *image.Fetcher
repoName string
repo string
outBuf bytes.Buffer
fetcher *image.Fetcher
repoName string
repo string
outBuf bytes.Buffer
runnableBaseImage string
)

it.Before(func() {
repo = "some-org/" + h.RandString(10)
repoName = registryConfig.RepoName(repo)
fetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker)

daemonInfo, err := docker.Info(context.TODO())
h.AssertNil(t, err)

runnableBaseImage = h.RunnableBaseImage(daemonInfo.OSType)
h.PullIfMissing(t, docker, runnableBaseImage)
})

when("#Fetch", func() {
Expand Down

0 comments on commit de26af4

Please sign in to comment.