diff --git a/client/pull.go b/client/pull.go index d86aa6ca9..2dfa8ff28 100644 --- a/client/pull.go +++ b/client/pull.go @@ -3,14 +3,13 @@ package client import ( "context" "fmt" - "time" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" "github.com/docker/distribution/reference" + "github.com/moby/buildkit/cache" + imageexporter "github.com/moby/buildkit/exporter/containerimage" "github.com/moby/buildkit/source" - "github.com/moby/buildkit/util/pull" + "github.com/moby/buildkit/source/containerimage" ) // Pull retrieves an image from a remote registry. @@ -36,36 +35,71 @@ func (c *Client) Pull(ctx context.Context, image string) (*ListedImage, error) { return nil, fmt.Errorf("creating worker opt failed: %v", err) } - puller := &pull.Puller{ + cm, err := cache.NewManager(cache.ManagerOpt{ + Snapshotter: opt.Snapshotter, + MetadataStore: opt.MetadataStore, + }) + if err != nil { + return nil, err + } + + // Create the source for the pull. + srcOpt := containerimage.SourceOpt{ + SessionManager: opt.SessionManager, + Snapshotter: opt.Snapshotter, + ContentStore: opt.ContentStore, + Applier: opt.Applier, + CacheAccessor: cm, + ImageStore: opt.ImageStore, + } + src, err := containerimage.NewSource(srcOpt) + if err != nil { + return nil, err + } + s, err := src.Resolve(ctx, identifier) + if err != nil { + return nil, err + } + ref, err := s.Snapshot(ctx) + if err != nil { + return nil, err + } + + // Create the exporter for the pull. + iw, err := imageexporter.NewImageWriter(imageexporter.WriterOpt{ Snapshotter: opt.Snapshotter, ContentStore: opt.ContentStore, - Applier: opt.Applier, - Src: identifier.Reference, - Resolver: pull.NewResolver(ctx, opt.SessionManager, opt.ImageStore), + Differ: opt.Differ, + }) + if err != nil { + return nil, err + } + expOpt := imageexporter.Opt{ + SessionManager: opt.SessionManager, + Images: opt.ImageStore, + ImageWriter: iw, } - pulled, err := puller.Pull(ctx) + exp, err := imageexporter.New(expOpt) if err != nil { return nil, err } - // Update the target image. Create it if it does not exist. - img := images.Image{ - Name: image, - Target: pulled.Descriptor, - CreatedAt: time.Now(), + e, err := exp.Resolve(ctx, map[string]string{"name": image}) + if err != nil { + return nil, err + } + if _, err := e.Export(ctx, ref, nil); err != nil { + return nil, err } - if _, err := opt.ImageStore.Update(ctx, img); err != nil { - if !errdefs.IsNotFound(err) { - return nil, fmt.Errorf("updating image store for %s failed: %v", image, err) - } - // Create it if we didn't find it. - if _, err := opt.ImageStore.Create(ctx, img); err != nil { - return nil, fmt.Errorf("creating image in image store for %s failed: %v", image, err) - } + // Get the image. + img, err := opt.ImageStore.Get(ctx, image) + if err != nil { + return nil, fmt.Errorf("getting image %s from image store failed: %v", image, err) } size, err := img.Size(ctx, opt.ContentStore, platforms.Default()) if err != nil { - return nil, fmt.Errorf("calculating size of image %s failed: %v", image, err) + return nil, fmt.Errorf("calculating size of image %s failed: %v", img.Name, err) } + return &ListedImage{Image: img, ContentSize: size}, nil } diff --git a/tag_test.go b/tag_test.go index ac867a806..ad281748e 100644 --- a/tag_test.go +++ b/tag_test.go @@ -19,3 +19,41 @@ func TestTagImage(t *testing.T) { t.Fatalf("expected ls output to have tagthing:latest and jess/tagtest:latest but got: %s", out) } } + +func TestTagImageAndPush(t *testing.T) { + runBuild(t, "tagthingandpush", withDockerfile(` + FROM busybox + RUN echo tagtestandpush + `)) + + run(t, "tag", "tagthingandpush", "jess/tagtestandpush") + + out := run(t, "ls") + + if !strings.Contains(out, "tagthingandpush:latest") || !strings.Contains(out, "jess/tagtestandpush:latest") { + t.Fatalf("expected ls output to have tagthingandpush:latest and jess/tagtestandpush:latest but got: %s", out) + } + + out, err := doRun([]string{"push", "jess/tagtestandpush"}, nil) + if !strings.Contains(err.Error(), "insufficient_scope: authorization failed") { + t.Fatalf("expected push to fail with 'insufficient_scope: authorization failed' got: %s %v", out, err) + } +} + +func TestTagPullAndPush(t *testing.T) { + // Test an official image, + run(t, "pull", "busybox") + + run(t, "tag", "busybox", "jess/tagpullandpush") + + out := run(t, "ls") + + if !strings.Contains(out, "busybox:latest") || !strings.Contains(out, "jess/tagpullandpush:latest") { + t.Fatalf("expected ls output to have busybox:latest and jess/tagpullandpush:latest but got: %s", out) + } + + out, err := doRun([]string{"push", "jess/tagpullandpush"}, nil) + if !strings.Contains(err.Error(), "insufficient_scope: authorization failed") { + t.Fatalf("expected push to fail with 'insufficient_scope: authorization failed' got: %s %v", out, err) + } +}