Skip to content

Commit d9bfbcb

Browse files
authored
crane pull: support pulling index to OCI Layout (#1215)
* 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
1 parent c636644 commit d9bfbcb

File tree

3 files changed

+65
-5
lines changed

3 files changed

+65
-5
lines changed

Diff for: .github/workflows/e2e.yaml

+18
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,21 @@ jobs:
6363
./app/crane pull --format=oci $img $layout
6464
./app/crane push --image-refs=foo.images $layout $dst
6565
diff <(./app/crane manifest $img) <(./app/crane manifest $(cat foo.images))
66+
67+
# Make sure we can roundtrip an index (distroless).
68+
distroless=$(mktemp -d)
69+
remote="gcr.io/distroless/static"
70+
local="localhost:1338/distroless:static"
71+
72+
./app/crane pull --format=oci $remote $distroless
73+
./app/crane push $distroless $local
74+
diff <(./app/crane manifest $remote) <(./app/crane manifest $local)
75+
76+
# And that it works for a single platform (pulling from what we just pushed).
77+
distroless=$(mktemp -d)
78+
remote="$local"
79+
local="localhost:1338/distroless/platform:static"
80+
81+
./app/crane pull --platform=linux/arm64 --format=oci $remote $distroless
82+
./app/crane push $distroless $local
83+
diff <(./app/crane manifest --platform linux/arm64 $remote) <(./app/crane manifest $local)

Diff for: cmd/crane/cmd/pull.go

+42-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ import (
1818
"fmt"
1919

2020
"github.com/google/go-containerregistry/pkg/crane"
21+
"github.com/google/go-containerregistry/pkg/name"
2122
v1 "github.com/google/go-containerregistry/pkg/v1"
2223
"github.com/google/go-containerregistry/pkg/v1/cache"
24+
"github.com/google/go-containerregistry/pkg/v1/layout"
25+
"github.com/google/go-containerregistry/pkg/v1/remote"
2326
"github.com/spf13/cobra"
2427
)
2528

@@ -33,16 +36,38 @@ func NewCmdPull(options *[]crane.Option) *cobra.Command {
3336
Args: cobra.MinimumNArgs(2),
3437
RunE: func(_ *cobra.Command, args []string) error {
3538
imageMap := map[string]v1.Image{}
39+
indexMap := map[string]v1.ImageIndex{}
3640
srcList, path := args[:len(args)-1], args[len(args)-1]
3741
for _, src := range srcList {
38-
img, err := crane.Pull(src, *options...)
42+
o := crane.GetOptions(*options...)
43+
ref, err := name.ParseReference(src, o.Name...)
3944
if err != nil {
40-
return fmt.Errorf("pulling %s: %w", src, err)
45+
return fmt.Errorf("parsing reference %q: %w", src, err)
46+
}
47+
48+
rmt, err := remote.Get(ref, o.Remote...)
49+
if err != nil {
50+
return err
51+
}
52+
53+
// If we're writing an index to a layout and --platform hasn't been set,
54+
// pull the entire index, not just a child image.
55+
if format == "oci" && rmt.MediaType.IsIndex() && o.Platform == nil {
56+
idx, err := rmt.ImageIndex()
57+
if err != nil {
58+
return err
59+
}
60+
indexMap[src] = idx
61+
continue
62+
}
63+
64+
img, err := rmt.Image()
65+
if err != nil {
66+
return err
4167
}
4268
if cachePath != "" {
4369
img = cache.Image(img, cache.NewFilesystemCache(cachePath))
4470
}
45-
4671
imageMap[src] = img
4772
}
4873

@@ -59,6 +84,20 @@ func NewCmdPull(options *[]crane.Option) *cobra.Command {
5984
if err := crane.MultiSaveOCI(imageMap, path); err != nil {
6085
return fmt.Errorf("saving oci image layout %s: %w", path, err)
6186
}
87+
88+
// crane.MultiSaveOCI doesn't support index, so just append these at the end.
89+
p, err := layout.FromPath(path)
90+
if err != nil {
91+
return err
92+
}
93+
for ref, idx := range indexMap {
94+
anns := map[string]string{
95+
"dev.ggcr.image.name": ref,
96+
}
97+
if err := p.AppendIndex(idx, layout.WithAnnotations(anns)); err != nil {
98+
return err
99+
}
100+
}
62101
default:
63102
return fmt.Errorf("unexpected --format: %q (valid values are: tarball, legacy, and oci)", format)
64103
}

Diff for: pkg/crane/pull.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ func MultiSaveOCI(imgMap map[string]v1.Image, path string) error {
133133
return err
134134
}
135135
}
136-
for _, img := range imgMap {
137-
if err = p.AppendImage(img); err != nil {
136+
for ref, img := range imgMap {
137+
anns := map[string]string{
138+
"dev.ggcr.image.name": ref,
139+
}
140+
if err = p.AppendImage(img, layout.WithAnnotations(anns)); err != nil {
138141
return err
139142
}
140143
}

0 commit comments

Comments
 (0)