diff --git a/pkg/imgpkg/cmd/copy_repo_src.go b/pkg/imgpkg/cmd/copy_repo_src.go index 0ed31a24..2b40296c 100644 --- a/pkg/imgpkg/cmd/copy_repo_src.go +++ b/pkg/imgpkg/cmd/copy_repo_src.go @@ -83,12 +83,18 @@ func (c CopyRepoSrc) CopyToRepo(repo string) (*ctlimgset.ProcessedImages, error) } err = image.ExtractOciTarGz(c.OciFlags.OcitoReg, tempDir) if err != nil { - return nil, err + return nil, fmt.Errorf("Extracting OCI tar: %s", err) } processedImages, err = c.tarImageSet.Import(tempDir, importRepo, c.registry, true) + if err != nil { + return nil, fmt.Errorf("Importing OCI tar: %s", err) + } } else { processedImages, err = c.tarImageSet.Import(c.TarFlags.TarSrc, importRepo, c.registry, false) + if err != nil { + return nil, fmt.Errorf("Importing tar: %s", err) + } } if err != nil { diff --git a/pkg/imgpkg/cmd/oci_flags.go b/pkg/imgpkg/cmd/oci_flags.go index 3c8baa0d..d6dbc09a 100644 --- a/pkg/imgpkg/cmd/oci_flags.go +++ b/pkg/imgpkg/cmd/oci_flags.go @@ -1,4 +1,4 @@ -// Copyright 2020 VMware, Inc. +// Copyright 2023 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 package cmd @@ -7,14 +7,17 @@ import ( "github.com/spf13/cobra" ) +// OciFlags is a struct that holds the flags for the OCI tar file. type OciFlags struct { OcitoReg string OciTar string } +// Set sets the flags for the OCI tar file. func (o *OciFlags) Set(cmd *cobra.Command) { cmd.Flags().StringVar(&o.OciTar, "to-oci-tar", "", "Set OciTarPath to be saved to disk (example: /path/file.tar)") cmd.Flags().StringVar(&o.OcitoReg, "oci-tar", "", "Give path to OCI tar file (example: /path/file.tar)") } +// IsOci returns true if the OCI tar file is set. func (o OciFlags) IsOci() bool { return o.OcitoReg != "" } diff --git a/pkg/imgpkg/image/tar_image.go b/pkg/imgpkg/image/tar_image.go index 0881f322..02257b44 100644 --- a/pkg/imgpkg/image/tar_image.go +++ b/pkg/imgpkg/image/tar_image.go @@ -182,6 +182,7 @@ func (i *TarImage) isExcluded(relPath string) bool { return false } +// CreateOciTarFileAndDeleteFolder creates a oci tar file from the source folder and deletes the source folder. Used while pushing the oci-tar func CreateOciTarFileAndDeleteFolder(source, target string) error { tarFile, err := os.Create(target) @@ -242,6 +243,7 @@ func CreateOciTarFileAndDeleteFolder(source, target string) error { return nil } +// ExtractOciTarGz extracts the oci tar file to the extractDir func ExtractOciTarGz(inputDir, extractDir string) error { if !strings.HasSuffix(inputDir, ".tar.gz") { diff --git a/pkg/imgpkg/imagedesc/image_intermediate.go b/pkg/imgpkg/imagedesc/image_intermediate.go index 59bc97dd..99445ddd 100644 --- a/pkg/imgpkg/imagedesc/image_intermediate.go +++ b/pkg/imgpkg/imagedesc/image_intermediate.go @@ -1,4 +1,4 @@ -// Copyright 2020 VMware, Inc. +// Copyright 2023 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 package imagedesc @@ -8,119 +8,145 @@ import ( "github.com/google/go-containerregistry/pkg/v1/types" ) -// intermediate struct for Image and ImageIndex to convert to imagwithref type for oci image +// ImageIndexIntermediate struct for ImageIndex to help in convertion to ImagIndexWithRef struct for oci image workflow.. type ImageIndexIntermediate struct { Index regv1.ImageIndex ref string tag string } +// ImageIntermediate struct for Image to help in convertion to ImageWithRef struct for oci image workflow. type ImageIntermediate struct { Image regv1.Image ref string tag string } +// Ref returns the reference in the imageintermediate struct. func (mi ImageIntermediate) Ref() string { return mi.ref } +// SetRef sets the reference in the imageintermediate struct. func (mi *ImageIntermediate) SetRef(ref string) { mi.ref = ref } +// Tag returns the tag value set in the imageintermediate struct. func (mi ImageIntermediate) Tag() string { return mi.tag } +// SetTag sets the tag value in the imageintermediate struct. func (mi *ImageIntermediate) SetTag(tag string) { mi.tag = tag } +// Layers returns the ordered collection of filesystem layers that comprise this image. func (mi ImageIntermediate) Layers() ([]regv1.Layer, error) { return mi.Image.Layers() } - +// MediaType of the image's manifest. func (mi ImageIntermediate) MediaType() (types.MediaType, error) { return mi.Image.MediaType() } +// Size returns the size of the image. func (mi ImageIntermediate) Size() (int64, error) { return mi.Image.Size() } +// ConfigName returns the name of the image's configuration. func (mi ImageIntermediate) ConfigName() (regv1.Hash, error) { return mi.Image.ConfigName() } +// ConfigFile returns the image's config file. func (mi ImageIntermediate) ConfigFile() (*regv1.ConfigFile, error) { return mi.Image.ConfigFile() } +// RawConfigFile returns the serialized bytes of ConfigFile(). func (mi ImageIntermediate) RawConfigFile() ([]byte, error) { return mi.Image.RawConfigFile() } +// Digest returns the sha256 of this image's manifest. func (mi ImageIntermediate) Digest() (regv1.Hash, error) { return mi.Image.Digest() } +// Manifest returns this image's Manifest object. func (mi ImageIntermediate) Manifest() (*regv1.Manifest, error) { return mi.Image.Manifest() } +// RawManifest returns the serialized bytes of Manifest() func (mi ImageIntermediate) RawManifest() ([]byte, error) { return mi.Image.RawManifest() } +// LayerByDigest returns a Layer for interacting with a particular layer of the image, looking it up by "digest" (the compressed hash). func (mi ImageIntermediate) LayerByDigest(h regv1.Hash) (regv1.Layer, error) { return mi.Image.LayerByDigest(h) } +// LayerByDiffID is an analog to LayerByDigest, looking up by "diff id" (the uncompressed hash). func (mi ImageIntermediate) LayerByDiffID(h regv1.Hash) (regv1.Layer, error) { return mi.Image.LayerByDiffID(h) } +// Ref returns the reference in the imageindexintermediate struct. func (mi ImageIndexIntermediate) Ref() string { return mi.ref } +// SetRef sets the reference in the imageindexintermediate struct. func (mi *ImageIndexIntermediate) SetRef(ref string) { mi.ref = ref } +// Tag returns the tag value set in the imageindexintermediate struct. func (mi ImageIndexIntermediate) Tag() string { return mi.tag } +// SetTag sets the tag value in the imageindexintermediate struct. func (mi *ImageIndexIntermediate) SetTag(tag string) { mi.tag = tag } +// MediaType of the imageindex's manifest. func (mi ImageIndexIntermediate) MediaType() (types.MediaType, error) { return mi.Index.MediaType() } +// Digest returns the sha256 of this imageindex's manifest. func (mi ImageIndexIntermediate) Digest() (regv1.Hash, error) { return mi.Index.Digest() } +// Size returns the size of the imageindex. func (mi ImageIndexIntermediate) Size() (int64, error) { return mi.Index.Size() } +// IndexManifest returns this image index's manifest object. func (mi ImageIndexIntermediate) IndexManifest() (*regv1.IndexManifest, error) { return mi.Index.IndexManifest() } +// RawManifest returns the serialized bytes of IndexManifest(). func (mi ImageIndexIntermediate) RawManifest() ([]byte, error) { return mi.Index.RawManifest() } +// Image returns a v1.Image that this ImageIndex references. func (mi ImageIndexIntermediate) Image(h regv1.Hash) (regv1.Image, error) { return mi.Index.Image(h) } +// ImageIndex returns a v1.ImageIndex that this ImageIndex references. func (mi ImageIndexIntermediate) ImageIndex(h regv1.Hash) (regv1.ImageIndex, error) { return mi.Index.ImageIndex(h) } diff --git a/pkg/imgpkg/imageset/image_set.go b/pkg/imgpkg/imageset/image_set.go index 6eaa8c67..fa6b6537 100644 --- a/pkg/imgpkg/imageset/image_set.go +++ b/pkg/imgpkg/imageset/image_set.go @@ -71,7 +71,6 @@ func (i ImageSet) Export(foundImages *UnprocessedImageRefs, return ids, nil } -// this pushes probably to a registry func (i *ImageSet) Import(imgOrIndexes []imagedesc.ImageOrIndex, importRepo regname.Repository, registry registry.ImagesReaderWriter) (*ProcessedImages, error) { diff --git a/pkg/imgpkg/imageset/tar_image_set.go b/pkg/imgpkg/imageset/tar_image_set.go index 1e608594..03f4671e 100644 --- a/pkg/imgpkg/imageset/tar_image_set.go +++ b/pkg/imgpkg/imageset/tar_image_set.go @@ -130,8 +130,14 @@ func (i *TarImageSet) Import(path string, importRepo regname.Repository, registr if tarisoci { imgOrIndexes, err = imagetar.NewTarReader(path).ReadOci(importRepo) + if err != nil { + return nil, err + } } else { imgOrIndexes, err = imagetar.NewTarReader(path).Read() + if err != nil { + return nil, err + } } processedImages, err := i.imageSet.Import(imgOrIndexes, importRepo, registry) diff --git a/pkg/imgpkg/imagetar/tar_reader.go b/pkg/imgpkg/imagetar/tar_reader.go index b7727234..40bbf6ae 100644 --- a/pkg/imgpkg/imagetar/tar_reader.go +++ b/pkg/imgpkg/imagetar/tar_reader.go @@ -35,6 +35,98 @@ func (r TarReader) Read() ([]imagedesc.ImageOrIndex, error) { return imagedesc.NewDescribedReader(ids, file).Read(), nil } +// ReadOci reads the OCI layout from the tar file and returns the image or index. Equivalent to Read() but for OCI layout +func (r TarReader) ReadOci(importRepo name.Repository) ([]imagedesc.ImageOrIndex, error) { + + stat, err := os.Stat(r.path) + if err != nil { + return nil, err + } + + if !stat.IsDir() { + return nil, fmt.Errorf("path %s is not a directory", r.path) + } + + _, err = os.Stat(filepath.Join(r.path, "oci-layout")) + if err != nil { + return nil, err + } + + l, err := layout.FromPath(r.path) + if err != nil { + return nil, err + } + + ii, err := l.ImageIndex() + if err != nil { + return nil, fmt.Errorf("Unable to read image index: %s", err) + } + m, err := ii.IndexManifest() + if err != nil { + return nil, fmt.Errorf("Unable to read index manifest: %s", err) + } + desc := m.Manifests[0] + + var ImageIntermediate imagedesc.ImageIntermediate + var ImageIndexIntermediate imagedesc.ImageIndexIntermediate + var ref string + + if desc.MediaType.IsImage() { + img, err := ii.Image(desc.Digest) + if err != nil { + return nil, err + } + + ImageIntermediate = imagedesc.ImageIntermediate{ + Image: img, + } + + digest, err := img.Digest() + if err != nil { + return nil, fmt.Errorf("Unable to get digest from image: %s", err) + } + digestStr := digest.String() + ref = importRepo.Name() + "@" + digestStr + + ImageIntermediate.SetRef(ref) + + } else if desc.MediaType.IsIndex() { + idx, err := ii.ImageIndex(desc.Digest) + if err != nil { + return nil, err + } + ImageIndexIntermediate = imagedesc.ImageIndexIntermediate{ + Index: idx, + } + + digest, err := idx.Digest() + if err != nil { + return nil, fmt.Errorf("Unable to get digest from index: %s", err) + } + digestStr := digest.String() + ref = importRepo.Name() + "@" + digestStr + ImageIndexIntermediate.SetRef(ref) + + } else { + return nil, fmt.Errorf("Unexpected media type: %s", desc.MediaType) + } + + var b imagedesc.ImageWithRef = ImageIntermediate + imageOrIndex := imagedesc.ImageOrIndex{ + Image: &b, + Index: nil, + Labels: map[string]string{ + "dev.carvel.imgpkg.copy.root-bundle": "", + }, + OrigRef: "", + } + + var imageOrIndexSlice []imagedesc.ImageOrIndex + imageOrIndexSlice = append(imageOrIndexSlice, imageOrIndex) + + return imageOrIndexSlice, nil +} + // PresentLayers retrieves all the layers that are present in a tar file func (r TarReader) PresentLayers() ([]v1.Layer, error) { var result []v1.Layer @@ -151,82 +243,3 @@ func (r TarReader) getIdsFromManifest(file tarFile) (*imagedesc.ImageRefDescript } return ids, nil } - -func (r TarReader) ReadOci(importRepo name.Repository) ([]imagedesc.ImageOrIndex, error) { - - stat, err := os.Stat(r.path) - if err != nil { - return nil, err - } - - if !stat.IsDir() { - return nil, fmt.Errorf("path %s is not a directory", r.path) - } - - _, err = os.Stat(filepath.Join(r.path, "oci-layout")) - if err != nil { - return nil, err - } - - l, err := layout.FromPath(r.path) - if err != nil { - return nil, err - } - - ii, err := l.ImageIndex() - m, err := ii.IndexManifest() - desc := m.Manifests[0] - - var ImageIntermediate imagedesc.ImageIntermediate - var ImageIndexIntermediate imagedesc.ImageIndexIntermediate - var ref string - - if desc.MediaType.IsImage() { - img, err := ii.Image(desc.Digest) - if err != nil { - return nil, err - } - - ImageIntermediate = imagedesc.ImageIntermediate{ - Image: img, - } - - digest, err := img.Digest() - digestStr := digest.String() - ref = importRepo.Name() + "@" + digestStr - - ImageIntermediate.SetRef(ref) - - } else if desc.MediaType.IsIndex() { - idx, err := ii.ImageIndex(desc.Digest) - if err != nil { - return nil, err - } - ImageIndexIntermediate = imagedesc.ImageIndexIntermediate{ - Index: idx, - } - - digest, err := idx.Digest() - digestStr := digest.String() - ref = importRepo.Name() + "@" + digestStr - ImageIndexIntermediate.SetRef(ref) - - } else { - return nil, fmt.Errorf("Unexpected media type: %s", desc.MediaType) - } - - var b imagedesc.ImageWithRef = ImageIntermediate - imageOrIndex := imagedesc.ImageOrIndex{ - Image: &b, - Index: nil, - Labels: map[string]string{ - "dev.carvel.imgpkg.copy.root-bundle": "", - }, - OrigRef: "", - } - - var imageOrIndexSlice []imagedesc.ImageOrIndex - imageOrIndexSlice = append(imageOrIndexSlice, imageOrIndex) - - return imageOrIndexSlice, nil -}