From ff858b91e6e91f787df8485b54db4e4ccdbb18e6 Mon Sep 17 00:00:00 2001 From: thesayyn Date: Wed, 17 Aug 2022 03:57:40 +0300 Subject: [PATCH] fix: consider base image media type when appending layers --- cmd/crane/cmd/append.go | 8 +++- cmd/crane/doc/crane_append.md | 1 + pkg/crane/append.go | 21 ++++++++-- pkg/crane/append_test.go | 73 +++++++++++++++++++++++++++++++++ pkg/crane/testdata/content.tar | Bin 0 -> 10240 bytes pkg/v1/stream/layer.go | 15 +++++-- pkg/v1/stream/layer_test.go | 13 ++++++ 7 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 pkg/crane/append_test.go create mode 100755 pkg/crane/testdata/content.tar diff --git a/cmd/crane/cmd/append.go b/cmd/crane/cmd/append.go index 4d4dda7f1..d374079ca 100644 --- a/cmd/crane/cmd/append.go +++ b/cmd/crane/cmd/append.go @@ -23,6 +23,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/types" specsv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/cobra" ) @@ -31,7 +32,7 @@ import ( func NewCmdAppend(options *[]crane.Option) *cobra.Command { var baseRef, newTag, outFile string var newLayers []string - var annotate bool + var annotate, oci bool appendCmd := &cobra.Command{ Use: "append", @@ -51,6 +52,10 @@ container image.`, if baseRef == "" { logs.Warn.Printf("base unspecified, using empty image") base = empty.Image + if oci { + base = mutate.MediaType(base, types.OCIManifestSchema1) + base = mutate.ConfigMediaType(base, types.OCIConfigJSON) + } } else { base, err = crane.Pull(baseRef, *options...) if err != nil { @@ -108,6 +113,7 @@ container image.`, appendCmd.Flags().StringSliceVarP(&newLayers, "new_layer", "f", []string{}, "Path to tarball to append to image") appendCmd.Flags().StringVarP(&outFile, "output", "o", "", "Path to new tarball of resulting image") appendCmd.Flags().BoolVar(&annotate, "set-base-image-annotations", false, "If true, annotate the resulting image as being based on the base image") + appendCmd.Flags().BoolVar(&oci, "oci", false, "If true, empty base image will have OCI media types instead of Docker") appendCmd.MarkFlagRequired("new_tag") appendCmd.MarkFlagRequired("new_layer") diff --git a/cmd/crane/doc/crane_append.md b/cmd/crane/doc/crane_append.md index a6690a301..255edab9f 100644 --- a/cmd/crane/doc/crane_append.md +++ b/cmd/crane/doc/crane_append.md @@ -23,6 +23,7 @@ crane append [flags] -h, --help help for append -f, --new_layer strings Path to tarball to append to image -t, --new_tag string Tag to apply to resulting image + --oci If true, empty base image will have OCI media types instead of Docker -o, --output string Path to new tarball of resulting image --set-base-image-annotations If true, annotate the resulting image as being based on the base image ``` diff --git a/pkg/crane/append.go b/pkg/crane/append.go index 92d6b7b3b..660d570b0 100644 --- a/pkg/crane/append.go +++ b/pkg/crane/append.go @@ -23,6 +23,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/stream" "github.com/google/go-containerregistry/pkg/v1/tarball" + "github.com/google/go-containerregistry/pkg/v1/types" ) func isWindows(img v1.Image) (bool, error) { @@ -47,9 +48,21 @@ func Append(base v1.Image, paths ...string) (v1.Image, error) { return nil, fmt.Errorf("getting base image: %w", err) } + baseMediaType, err := base.MediaType() + + if err != nil { + return nil, fmt.Errorf("getting base image media type: %w", err) + } + + layerType := types.DockerLayer + + if baseMediaType == types.OCIManifestSchema1 { + layerType = types.OCILayer + } + layers := make([]v1.Layer, 0, len(paths)) for _, path := range paths { - layer, err := getLayer(path) + layer, err := getLayer(path, layerType) if err != nil { return nil, fmt.Errorf("reading layer %q: %w", path, err) } @@ -67,16 +80,16 @@ func Append(base v1.Image, paths ...string) (v1.Image, error) { return mutate.AppendLayers(base, layers...) } -func getLayer(path string) (v1.Layer, error) { +func getLayer(path string, layerType types.MediaType) (v1.Layer, error) { f, err := streamFile(path) if err != nil { return nil, err } if f != nil { - return stream.NewLayer(f), nil + return stream.NewLayer(f, stream.WithMediaType(layerType)), nil } - return tarball.LayerFromFile(path) + return tarball.LayerFromFile(path, tarball.WithMediaType(layerType)) } // If we're dealing with a named pipe, trying to open it multiple times will diff --git a/pkg/crane/append_test.go b/pkg/crane/append_test.go new file mode 100644 index 000000000..d894a9dac --- /dev/null +++ b/pkg/crane/append_test.go @@ -0,0 +1,73 @@ +// Copyright 2022 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crane_test + +import ( + "testing" + + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/types" +) + +func TestAppendWithOCIBaseImage(t *testing.T) { + base := mutate.MediaType(empty.Image, types.OCIManifestSchema1) + img, err := crane.Append(base, "testdata/content.tar") + + if err != nil { + t.Fatalf("crane.Append(): %v", err) + } + + layers, err := img.Layers() + + if err != nil { + t.Fatalf("img.Layers(): %v", err) + } + + mediaType, err := layers[0].MediaType() + + if err != nil { + t.Fatalf("layers[0].MediaType(): %v", err) + } + + if got, want := mediaType, types.OCILayer; got != want { + t.Errorf("MediaType(): want %q, got %q", want, got) + } +} + +func TestAppendWithDockerBaseImage(t *testing.T) { + img, err := crane.Append(empty.Image, "testdata/content.tar") + + if err != nil { + t.Fatalf("crane.Append(): %v", err) + } + + layers, err := img.Layers() + + if err != nil { + t.Fatalf("img.Layers(): %v", err) + } + + mediaType, err := layers[0].MediaType() + + if err != nil { + t.Fatalf("layers[0].MediaType(): %v", err) + } + + if got, want := mediaType, types.DockerLayer; got != want { + t.Errorf("MediaType(): want %q, got %q", want, got) + } +} diff --git a/pkg/crane/testdata/content.tar b/pkg/crane/testdata/content.tar new file mode 100755 index 0000000000000000000000000000000000000000..55f4d1db159638f9414cf03329fe4ae519fef60b GIT binary patch literal 10240 zcmeIxu?>VU3_#J;H$^6Z2ne1BMgXq4>CZuc5CsLu5fa}`q7=6CEElCSkDwtjx^!wB z&;8qSmpW9=NAu3Kz;~Rw!TZ~#Qs)}m=WZv=lb|U3ZZa;FT;l2co0V-L6lq)MgK=MT z`j^jNr~k>pOpRv>r2YRHw{~U!rD6Y#$19hYips9fX0tg_000IagfB*srAb