Skip to content

Commit

Permalink
Merge pull request #622 from carvel-dev/update-describe-cmd
Browse files Browse the repository at this point in the history
Updated describe command to show layer's digest of each image
  • Loading branch information
kumaritanushree authored Jan 18, 2024
2 parents 671367f + f2dc7d3 commit e5a7483
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 45 deletions.
8 changes: 8 additions & 0 deletions pkg/imgpkg/cmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ func (p bundleTextPrinter) printerRec(description v1.Description, originalLogger
indentLogger.Logf("- Image: %s\n", b.Image)
indentLogger.Logf(" Type: Bundle\n")
indentLogger.Logf(" Origin: %s\n", b.Origin)
indentLogger.Logf(" Layers:\n")
for _, d := range b.Layers {
indentLogger.Logf(" - Digest: %s\n", d.Digest)
}
annotations := b.Annotations

p.printAnnotations(annotations, util.NewIndentedLogger(indentLogger))
Expand All @@ -160,6 +164,10 @@ func (p bundleTextPrinter) printerRec(description v1.Description, originalLogger
if image.ImageType == bundle.ContentImage {
indentLogger.Logf(" Origin: %s\n", image.Origin)
}
indentLogger.Logf(" Layers:\n")
for _, d := range image.Layers {
indentLogger.Logf(" - Digest: %s\n", d.Digest)
}
annotations := image.Annotations
p.printAnnotations(annotations, util.NewIndentedLogger(indentLogger))
}
Expand Down
72 changes: 62 additions & 10 deletions pkg/imgpkg/v1/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import (
"carvel.dev/imgpkg/pkg/imgpkg/lockconfig"
"carvel.dev/imgpkg/pkg/imgpkg/registry"
"carvel.dev/imgpkg/pkg/imgpkg/signature"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
regname "github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
)

// Author information from a Bundle
Expand All @@ -33,13 +36,19 @@ type Metadata struct {
Websites []Website `json:"websites,omitempty"`
}

// Layers image layers info
type Layers struct {
Digest string `json:"digest,omitempty"`
}

// ImageInfo URLs where the image can be found as well as annotations provided in the Images Lock
type ImageInfo struct {
Image string `json:"image,omitempty"`
Origin string `json:"origin,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
ImageType bundle.ImageType `json:"imageType"`
Error string `json:"error,omitempty"`
Layers []Layers `json:"layers,omitempty"`
}

// Content Contents present in a Bundle
Expand All @@ -55,6 +64,7 @@ type Description struct {
Annotations map[string]string `json:"annotations,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
Content Content `json:"content"`
Layers []Layers `json:"layers,omitempty"`
}

// DescribeOpts Options used when calling the Describe function
Expand Down Expand Up @@ -106,23 +116,28 @@ func DescribeWithRegistryAndSignatureFetcher(bundleImage string, opts DescribeOp
topBundle := refWithDescription{
imgRef: bundle.NewBundleImageRef(lockconfig.ImageRef{Image: newBundle.DigestRef()}),
}
return topBundle.DescribeBundle(allBundles), nil
return topBundle.DescribeBundle(allBundles)
}

type refWithDescription struct {
imgRef bundle.ImageRef
bundle Description
}

func (r *refWithDescription) DescribeBundle(bundles []*bundle.Bundle) Description {
func (r *refWithDescription) DescribeBundle(bundles []*bundle.Bundle) (Description, error) {
var visitedImgs map[string]refWithDescription
return r.describeBundleRec(visitedImgs, r.imgRef, bundles)
}

func (r *refWithDescription) describeBundleRec(visitedImgs map[string]refWithDescription, currentBundle bundle.ImageRef, bundles []*bundle.Bundle) Description {
func (r *refWithDescription) describeBundleRec(visitedImgs map[string]refWithDescription, currentBundle bundle.ImageRef, bundles []*bundle.Bundle) (Description, error) {
desc, wasVisited := visitedImgs[currentBundle.Image]
if wasVisited {
return desc.bundle
return desc.bundle, nil
}

layers, err := getImageLayersInfo(currentBundle.Image)
if err != nil {
return desc.bundle, err
}

desc = refWithDescription{
Expand All @@ -136,6 +151,7 @@ func (r *refWithDescription) describeBundleRec(visitedImgs map[string]refWithDes
Bundles: map[string]Description{},
Images: map[string]ImageInfo{},
},
Layers: layers,
},
}
var newBundle *bundle.Bundle
Expand All @@ -146,7 +162,7 @@ func (r *refWithDescription) describeBundleRec(visitedImgs map[string]refWithDes
}
}
if newBundle == nil {
panic(fmt.Sprintf("Internal consistency: bundle with ref '%s' could not be found in list of bundles", currentBundle.PrimaryLocation()))
return desc.bundle, fmt.Errorf("Internal inconsistency: bundle with ref '%s' could not be found in list of bundles", currentBundle.PrimaryLocation())
}

imagesRefs := newBundle.ImagesRefsWithErrors()
Expand All @@ -156,27 +172,36 @@ func (r *refWithDescription) describeBundleRec(visitedImgs map[string]refWithDes

for _, ref := range imagesRefs {
if ref.IsBundle == nil {
panic("Internal consistency: IsBundle after processing must always have a value")
return desc.bundle, fmt.Errorf("Internal inconsistency: IsBundle after processing must always have a value")
}

if *ref.IsBundle {
bundleDesc := r.describeBundleRec(visitedImgs, ref, bundles)
bundleDesc, err := r.describeBundleRec(visitedImgs, ref, bundles)
if err != nil {
return desc.bundle, err
}

digest, err := name.NewDigest(bundleDesc.Image)
if err != nil {
panic(fmt.Sprintf("Internal inconsistency: image %s should be fully resolved", bundleDesc.Image))
return desc.bundle, fmt.Errorf("Internal inconsistency: image %s should be fully resolved", bundleDesc.Image)
}
desc.bundle.Content.Bundles[digest.DigestStr()] = bundleDesc
} else {
if ref.Error == "" {
digest, err := name.NewDigest(ref.Image)
if err != nil {
panic(fmt.Sprintf("Internal inconsistency: image %s should be fully resolved", ref.Image))
return desc.bundle, fmt.Errorf("Internal inconsistency: image %s should be fully resolved", ref.Image)
}
layers, err = getImageLayersInfo(ref.Image)
if err != nil {
return desc.bundle, err
}
desc.bundle.Content.Images[digest.DigestStr()] = ImageInfo{
Image: ref.PrimaryLocation(),
Origin: ref.Image,
Annotations: ref.Annotations,
ImageType: ref.ImageType,
Layers: layers,
}
} else {
desc.bundle.Content.Images[ref.Image] = ImageInfo{
Expand All @@ -187,5 +212,32 @@ func (r *refWithDescription) describeBundleRec(visitedImgs map[string]refWithDes
}
}

return desc.bundle
return desc.bundle, nil
}

func getImageLayersInfo(image string) ([]Layers, error) {
layers := []Layers{}
parsedImgRef, err := regname.ParseReference(image, regname.WeakValidation)
if err != nil {
return nil, fmt.Errorf("Error: %s in parsing image %s", err.Error(), image)
}

v1Img, err := remote.Image(parsedImgRef, remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
return nil, fmt.Errorf("Error: %s in getting remote access of image %s", err.Error(), image)
}

imgLayers, err := v1Img.Layers()
if err != nil {
return nil, fmt.Errorf("Error: %s in getting layers of image %s", err.Error(), image)
}

for _, imgLayer := range imgLayers {
digHash, err := imgLayer.Digest()
if err != nil {
return nil, fmt.Errorf("Error: %s in getting digest of layer's of image %s", err.Error(), image)
}
layers = append(layers, Layers{Digest: digHash.String()})
}
return layers, nil
}
Loading

0 comments on commit e5a7483

Please sign in to comment.