Skip to content

Commit

Permalink
crane pull: support pulling index to OCI Layout (#1215)
Browse files Browse the repository at this point in the history
* crane pull: support pulling index to OCI Layout

Prior to this, we'd also resolve an index to an image when using crane
pull. For OCI Layouts, we can actually pull the whole index, so when
--format=oci and --platform is unset, just do that.

* Address feedback

* Add platform test
  • Loading branch information
jonjohnsonjr authored Jan 5, 2022
1 parent c636644 commit d9bfbcb
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 5 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,21 @@ jobs:
./app/crane pull --format=oci $img $layout
./app/crane push --image-refs=foo.images $layout $dst
diff <(./app/crane manifest $img) <(./app/crane manifest $(cat foo.images))
# Make sure we can roundtrip an index (distroless).
distroless=$(mktemp -d)
remote="gcr.io/distroless/static"
local="localhost:1338/distroless:static"
./app/crane pull --format=oci $remote $distroless
./app/crane push $distroless $local
diff <(./app/crane manifest $remote) <(./app/crane manifest $local)
# And that it works for a single platform (pulling from what we just pushed).
distroless=$(mktemp -d)
remote="$local"
local="localhost:1338/distroless/platform:static"
./app/crane pull --platform=linux/arm64 --format=oci $remote $distroless
./app/crane push $distroless $local
diff <(./app/crane manifest --platform linux/arm64 $remote) <(./app/crane manifest $local)
45 changes: 42 additions & 3 deletions cmd/crane/cmd/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import (
"fmt"

"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/cache"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/spf13/cobra"
)

Expand All @@ -33,16 +36,38 @@ func NewCmdPull(options *[]crane.Option) *cobra.Command {
Args: cobra.MinimumNArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
imageMap := map[string]v1.Image{}
indexMap := map[string]v1.ImageIndex{}
srcList, path := args[:len(args)-1], args[len(args)-1]
for _, src := range srcList {
img, err := crane.Pull(src, *options...)
o := crane.GetOptions(*options...)
ref, err := name.ParseReference(src, o.Name...)
if err != nil {
return fmt.Errorf("pulling %s: %w", src, err)
return fmt.Errorf("parsing reference %q: %w", src, err)
}

rmt, err := remote.Get(ref, o.Remote...)
if err != nil {
return err
}

// If we're writing an index to a layout and --platform hasn't been set,
// pull the entire index, not just a child image.
if format == "oci" && rmt.MediaType.IsIndex() && o.Platform == nil {
idx, err := rmt.ImageIndex()
if err != nil {
return err
}
indexMap[src] = idx
continue
}

img, err := rmt.Image()
if err != nil {
return err
}
if cachePath != "" {
img = cache.Image(img, cache.NewFilesystemCache(cachePath))
}

imageMap[src] = img
}

Expand All @@ -59,6 +84,20 @@ func NewCmdPull(options *[]crane.Option) *cobra.Command {
if err := crane.MultiSaveOCI(imageMap, path); err != nil {
return fmt.Errorf("saving oci image layout %s: %w", path, err)
}

// crane.MultiSaveOCI doesn't support index, so just append these at the end.
p, err := layout.FromPath(path)
if err != nil {
return err
}
for ref, idx := range indexMap {
anns := map[string]string{
"dev.ggcr.image.name": ref,
}
if err := p.AppendIndex(idx, layout.WithAnnotations(anns)); err != nil {
return err
}
}
default:
return fmt.Errorf("unexpected --format: %q (valid values are: tarball, legacy, and oci)", format)
}
Expand Down
7 changes: 5 additions & 2 deletions pkg/crane/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ func MultiSaveOCI(imgMap map[string]v1.Image, path string) error {
return err
}
}
for _, img := range imgMap {
if err = p.AppendImage(img); err != nil {
for ref, img := range imgMap {
anns := map[string]string{
"dev.ggcr.image.name": ref,
}
if err = p.AppendImage(img, layout.WithAnnotations(anns)); err != nil {
return err
}
}
Expand Down

0 comments on commit d9bfbcb

Please sign in to comment.