Skip to content

Instantly share code, notes, and snippets.

@02strich
Created May 22, 2023 15:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 02strich/9917a31f407f0419fa762735c9770dca to your computer and use it in GitHub Desktop.
Save 02strich/9917a31f407f0419fa762735c9770dca to your computer and use it in GitHub Desktop.
package tools
import (
"context"
"fmt"
"os"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/chkk-io/addon-hub/pkg/addons/addonsiface"
"github.com/chkk-io/addon-hub/pkg/addons/sources"
"github.com/chkk-io/common-go/pkg/utils"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
log "github.com/sirupsen/logrus"
)
func CollectHashes(ctx context.Context, logger *log.Entry, addonDefinitions []sources.RegisteredSource) (string, error) {
remoteOpts := []remote.Option{
remote.WithAuthFromKeychain(authn.DefaultKeychain),
}
for _, addon := range addonDefinitions {
digests := make(map[string]*addonsiface.ImageDetails)
for _, registry := range addon.SourceDefinition.PublicRegistries {
repo, err := name.NewRepository(registry.URL)
if err != nil {
log.WithError(err).Errorf("Failed to create repository reference for %s", registry.URL)
continue
}
puller, err := remote.NewPuller(remoteOpts...)
if err != nil {
log.WithError(err).Errorf("Failed to pull repository %s", registry.URL)
continue
}
lister, err := puller.Lister(ctx, repo)
if err != nil {
log.WithError(err).Errorf("Failed to list tags for %s", registry.URL)
continue
}
for lister.HasNext() {
tags, err := lister.Next(ctx)
if err != nil {
log.WithError(err).Error("failed to get next entry")
} else {
for _, tag := range tags.Tags {
name, err := name.ParseReference(fmt.Sprintf("%s:%s", registry.URL, tag))
if err != nil {
log.WithError(err).Error("Failed to parse image reference")
continue
}
descr, err := puller.Get(ctx, name)
if err != nil {
log.WithError(err).Errorf("Failed to retrieve image details for %s", name)
continue
}
// parse version
parsedVersion := ""
v, err := semver.NewVersion(tag)
if err == nil {
parsedVersion = fmt.Sprintf("%d.%d.%d", v.Major(), v.Minor(), v.Patch())
}
// create new object or add to an existing one
var currentDigest *addonsiface.ImageDetails
if _, ok := digests[descr.Digest.Hex]; ok {
currentDigest = digests[descr.Digest.Hex]
currentDigest.Names = append(currentDigest.Names, name.String())
if !utils.ContainsStringArray(currentDigest.Versions, parsedVersion) {
currentDigest.Versions = append(currentDigest.Versions, parsedVersion)
}
} else {
currentDigest = &addonsiface.ImageDetails{Names: []string{name.String()}, Versions: []string{parsedVersion}, Digest: descr.Digest.Hex, Size: descr.Size, Layers: make([]addonsiface.ImageLayer, 0), SubManifests: make([]addonsiface.ImageSubManifestReference, 0)}
digests[descr.Digest.Hex] = currentDigest
}
// see whether we got an index file
index, err := descr.ImageIndex()
if index != nil {
indexManifest, err := index.IndexManifest()
if err != nil {
log.WithError(err).Errorf("Failed to parse index manifest data")
continue
}
for _, manifestReference := range indexManifest.Manifests {
submanifestReference := addonsiface.ImageSubManifestReference{
Digest: manifestReference.Digest.Hex,
Size: manifestReference.Size,
}
if manifestReference.Platform != nil {
submanifestReference.PlatformArchitecture = manifestReference.Platform.Architecture
submanifestReference.PlatformOs = manifestReference.Platform.OS
submanifestReference.PlatformOsVersion = manifestReference.Platform.OSVersion
}
currentDigest.SubManifests = append(currentDigest.SubManifests, submanifestReference)
}
} else {
// just an image
image, err := descr.Image()
if err != nil {
log.WithError(err).Errorf("Failed to parse image data")
continue
}
imageManifest, err := image.Manifest()
if err != nil {
log.WithError(err).Errorf("Failed to parse image manifest data")
continue
}
for _, layer := range imageManifest.Layers {
currentDigest.Layers = append(currentDigest.Layers, addonsiface.ImageLayer{
Digest: layer.Digest.Hex,
Size: layer.Size,
})
}
}
}
}
}
}
}
return "", nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment