2020-06-26 14:09:10 -05:00
|
|
|
package search
|
|
|
|
|
2022-07-15 06:10:51 -05:00
|
|
|
// This file will not be regenerated automatically.
|
|
|
|
//
|
|
|
|
// It serves as dependency injection for your app, add any dependencies you require here.
|
2020-06-26 14:09:10 -05:00
|
|
|
|
|
|
|
import (
|
2022-07-12 07:58:04 -05:00
|
|
|
"sort"
|
2021-01-25 13:04:03 -05:00
|
|
|
"strconv"
|
2022-07-12 07:58:04 -05:00
|
|
|
"strings"
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
2021-01-25 13:04:03 -05:00
|
|
|
godigest "github.com/opencontainers/go-digest"
|
2022-03-21 12:37:23 -05:00
|
|
|
"zotregistry.io/zot/pkg/log" // nolint: gci
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/pkg/extensions/search/common"
|
|
|
|
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
|
|
|
digestinfo "zotregistry.io/zot/pkg/extensions/search/digest"
|
2022-07-15 06:10:51 -05:00
|
|
|
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/pkg/storage"
|
2020-06-26 14:09:10 -05:00
|
|
|
) // THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.
|
|
|
|
|
|
|
|
// Resolver ...
|
|
|
|
type Resolver struct {
|
2021-04-05 19:40:33 -05:00
|
|
|
cveInfo *cveinfo.CveInfo
|
|
|
|
storeController storage.StoreController
|
2021-05-26 12:22:31 -05:00
|
|
|
digestInfo *digestinfo.DigestInfo
|
2021-01-25 13:04:03 -05:00
|
|
|
log log.Logger
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
type cveDetail struct {
|
|
|
|
Title string
|
|
|
|
Description string
|
|
|
|
Severity string
|
2022-07-15 06:10:51 -05:00
|
|
|
PackageList []*gql_generated.PackageInfo
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetResolverConfig ...
|
2022-07-15 06:10:51 -05:00
|
|
|
func GetResolverConfig(log log.Logger, storeController storage.StoreController, enableCVE bool) gql_generated.Config {
|
2021-01-25 13:04:03 -05:00
|
|
|
var cveInfo *cveinfo.CveInfo
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
if enableCVE {
|
|
|
|
cveInfo, err = cveinfo.GetCVEInfo(storeController, log)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
|
|
|
|
2021-09-30 08:27:13 -05:00
|
|
|
digestInfo := digestinfo.NewDigestInfo(storeController, log)
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2021-01-25 13:04:03 -05:00
|
|
|
resConfig := &Resolver{cveInfo: cveInfo, storeController: storeController, digestInfo: digestInfo, log: log}
|
|
|
|
|
2022-07-15 06:10:51 -05:00
|
|
|
return gql_generated.Config{
|
|
|
|
Resolvers: resConfig, Directives: gql_generated.DirectiveRoot{},
|
|
|
|
Complexity: gql_generated.ComplexityRoot{},
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2021-12-13 14:23:31 -05:00
|
|
|
func (r *queryResolver) getImageListForCVE(repoList []string, cvid string, imgStore storage.ImageStore,
|
2022-03-21 12:37:23 -05:00
|
|
|
trivyCtx *cveinfo.TrivyCtx,
|
2022-01-19 10:57:10 -05:00
|
|
|
) ([]*gql_generated.ImageSummary, error) {
|
|
|
|
cveResult := []*gql_generated.ImageSummary{}
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2021-04-05 19:40:33 -05:00
|
|
|
for _, repo := range repoList {
|
2021-01-25 13:04:03 -05:00
|
|
|
r.log.Info().Str("repo", repo).Msg("extracting list of tags available in image repo")
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
imageListByCVE, err := r.cveInfo.GetImageListForCVE(repo, cvid, imgStore, trivyCtx)
|
2021-04-05 19:40:33 -05:00
|
|
|
if err != nil {
|
2021-01-25 13:04:03 -05:00
|
|
|
r.log.Error().Err(err).Msg("error getting tag")
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2021-04-05 19:40:33 -05:00
|
|
|
return cveResult, err
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
for _, imageByCVE := range imageListByCVE {
|
|
|
|
cveResult = append(
|
|
|
|
cveResult,
|
|
|
|
buildImageInfo(repo, imageByCVE.Tag, imageByCVE.Digest, imageByCVE.Manifest),
|
|
|
|
)
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cveResult, nil
|
|
|
|
}
|
2020-08-19 01:53:04 -05:00
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
func (r *queryResolver) getImageListForDigest(repoList []string, digest string) ([]*gql_generated.ImageSummary, error) {
|
|
|
|
imgResultForDigest := []*gql_generated.ImageSummary{}
|
2021-05-26 12:22:31 -05:00
|
|
|
|
|
|
|
var errResult error
|
|
|
|
|
|
|
|
for _, repo := range repoList {
|
2021-01-25 13:04:03 -05:00
|
|
|
r.log.Info().Str("repo", repo).Msg("filtering list of tags in image repo by digest")
|
2021-05-26 12:22:31 -05:00
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
imgTags, err := r.digestInfo.GetImageTagsByDigest(repo, digest)
|
2021-05-26 12:22:31 -05:00
|
|
|
if err != nil {
|
2021-01-25 13:04:03 -05:00
|
|
|
r.log.Error().Err(err).Msg("unable to get filtered list of image tags")
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
return []*gql_generated.ImageSummary{}, err
|
2021-05-26 12:22:31 -05:00
|
|
|
}
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
for _, imageInfo := range imgTags {
|
|
|
|
imageInfo := buildImageInfo(repo, imageInfo.Tag, imageInfo.Digest, imageInfo.Manifest)
|
|
|
|
imgResultForDigest = append(imgResultForDigest, imageInfo)
|
2021-05-26 12:22:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return imgResultForDigest, errResult
|
|
|
|
}
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
func (r *queryResolver) getImageListWithLatestTag(store storage.ImageStore) ([]*gql_generated.ImageSummary, error) {
|
|
|
|
results := make([]*gql_generated.ImageSummary, 0)
|
2021-01-25 13:04:03 -05:00
|
|
|
|
|
|
|
repoList, err := store.GetRepositories()
|
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error extracting repositories list")
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(repoList) == 0 {
|
|
|
|
r.log.Info().Msg("no repositories found")
|
|
|
|
}
|
|
|
|
|
2022-07-12 07:58:04 -05:00
|
|
|
layoutUtils := common.NewBaseOciLayoutUtils(r.storeController, r.log)
|
2021-01-25 13:04:03 -05:00
|
|
|
|
|
|
|
for _, repo := range repoList {
|
2021-09-30 08:27:13 -05:00
|
|
|
tagsInfo, err := layoutUtils.GetImageTagsWithTimestamp(repo)
|
2021-01-25 13:04:03 -05:00
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error getting tag timestamp info")
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(tagsInfo) == 0 {
|
|
|
|
r.log.Info().Str("no tagsinfo found for repo", repo).Msg(" continuing traversing")
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
latestTag := common.GetLatestTag(tagsInfo)
|
|
|
|
|
|
|
|
digest := godigest.Digest(latestTag.Digest)
|
|
|
|
|
2021-09-30 08:27:13 -05:00
|
|
|
manifest, err := layoutUtils.GetImageBlobManifest(repo, digest)
|
2021-01-25 13:04:03 -05:00
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error reading manifest")
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
size := strconv.FormatInt(manifest.Config.Size, 10)
|
|
|
|
|
|
|
|
name := repo
|
|
|
|
|
2021-09-30 08:27:13 -05:00
|
|
|
imageConfig, err := layoutUtils.GetImageInfo(repo, manifest.Config.Digest)
|
2021-01-25 13:04:03 -05:00
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error reading image config")
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
labels := imageConfig.Config.Labels
|
|
|
|
|
|
|
|
// Read Description
|
|
|
|
desc := common.GetDescription(labels)
|
|
|
|
|
|
|
|
// Read licenses
|
|
|
|
license := common.GetLicense(labels)
|
|
|
|
|
|
|
|
// Read vendor
|
|
|
|
vendor := common.GetVendor(labels)
|
|
|
|
|
|
|
|
// Read categories
|
|
|
|
categories := common.GetCategories(labels)
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
results = append(results, &gql_generated.ImageSummary{
|
|
|
|
RepoName: &name, Tag: &latestTag.Name,
|
2021-01-25 13:04:03 -05:00
|
|
|
Description: &desc, Licenses: &license, Vendor: &vendor,
|
|
|
|
Labels: &categories, Size: &size, LastUpdated: &latestTag.Timestamp,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
2022-07-12 07:58:04 -05:00
|
|
|
func cleanQuerry(query string) string {
|
|
|
|
query = strings.ToLower(query)
|
|
|
|
query = strings.Replace(query, ":", " ", 1)
|
|
|
|
|
|
|
|
return query
|
|
|
|
}
|
|
|
|
|
|
|
|
func globalSearch(repoList []string, name, tag string, olu common.OciLayoutUtils, log log.Logger) (
|
|
|
|
[]*gql_generated.RepoSummary, []*gql_generated.ImageSummary, []*gql_generated.LayerSummary,
|
|
|
|
) {
|
|
|
|
repos := []*gql_generated.RepoSummary{}
|
|
|
|
images := []*gql_generated.ImageSummary{}
|
|
|
|
layers := []*gql_generated.LayerSummary{}
|
|
|
|
|
|
|
|
for _, repo := range repoList {
|
|
|
|
repo := repo
|
|
|
|
|
|
|
|
// map used for dedube if 2 images reference the same blob
|
2022-07-20 04:30:34 -05:00
|
|
|
repoBlob2Size := make(map[string]int64, 10)
|
2022-07-12 07:58:04 -05:00
|
|
|
|
|
|
|
// made up of all manifests, configs and image layers
|
|
|
|
repoSize := int64(0)
|
|
|
|
|
2022-07-22 15:01:38 -05:00
|
|
|
lastUpdatedTag, err := olu.GetRepoLastUpdated(repo)
|
2022-07-12 07:58:04 -05:00
|
|
|
if err != nil {
|
2022-07-22 15:01:38 -05:00
|
|
|
log.Error().Err(err).Msgf("can't find latest updated tag for repo: %s", repo)
|
2022-07-12 07:58:04 -05:00
|
|
|
}
|
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
manifests, err := olu.GetImageManifests(repo)
|
2022-07-12 07:58:04 -05:00
|
|
|
if err != nil {
|
2022-08-02 10:58:30 -05:00
|
|
|
log.Error().Err(err).Msgf("can't get manifests for repo: %s", repo)
|
2022-07-12 07:58:04 -05:00
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-07-22 15:01:38 -05:00
|
|
|
var lastUpdatedImageSummary gql_generated.ImageSummary
|
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
repoPlatforms := make([]*gql_generated.OsArch, 0, len(manifests))
|
|
|
|
repoVendors := make([]*string, 0, len(manifests))
|
2022-07-12 07:58:04 -05:00
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
for i, manifest := range manifests {
|
2022-07-12 07:58:04 -05:00
|
|
|
imageLayersSize := int64(0)
|
2022-07-20 04:30:34 -05:00
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
manifestTag, ok := manifest.Annotations[ispec.AnnotationRefName]
|
|
|
|
if !ok {
|
|
|
|
log.Error().Msg("reference not found for this manifest")
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
imageBlobManifest, err := olu.GetImageBlobManifest(repo, manifests[i].Digest)
|
2022-07-20 04:30:34 -05:00
|
|
|
if err != nil {
|
2022-08-02 10:58:30 -05:00
|
|
|
log.Error().Err(err).Msgf("can't read manifest for repo %s %s", repo, manifestTag)
|
2022-07-20 04:30:34 -05:00
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
manifestSize := olu.GetImageManifestSize(repo, manifests[i].Digest)
|
2022-07-20 04:30:34 -05:00
|
|
|
configSize := imageBlobManifest.Config.Size
|
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
repoBlob2Size[manifests[i].Digest.String()] = manifestSize
|
2022-07-20 04:30:34 -05:00
|
|
|
repoBlob2Size[imageBlobManifest.Config.Digest.Hex] = configSize
|
2022-07-12 07:58:04 -05:00
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
for _, layer := range imageBlobManifest.Layers {
|
2022-07-12 07:58:04 -05:00
|
|
|
layer := layer
|
2022-08-02 10:58:30 -05:00
|
|
|
layerDigest := layer.Digest.String()
|
|
|
|
layerSizeStr := strconv.Itoa(int(layer.Size))
|
|
|
|
repoBlob2Size[layer.Digest.String()] = layer.Size
|
|
|
|
imageLayersSize += layer.Size
|
2022-07-12 07:58:04 -05:00
|
|
|
|
|
|
|
// if we have a tag we won't match a layer
|
|
|
|
if tag != "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
if index := strings.Index(layerDigest, name); index != -1 {
|
2022-07-12 07:58:04 -05:00
|
|
|
layers = append(layers, &gql_generated.LayerSummary{
|
2022-08-02 10:58:30 -05:00
|
|
|
Digest: &layerDigest,
|
|
|
|
Size: &layerSizeStr,
|
2022-07-12 07:58:04 -05:00
|
|
|
Score: &index,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
imageSize := imageLayersSize + manifestSize + configSize
|
|
|
|
|
|
|
|
index := strings.Index(repo, name)
|
2022-08-02 10:58:30 -05:00
|
|
|
matchesTag := strings.HasPrefix(manifestTag, tag)
|
2022-07-12 07:58:04 -05:00
|
|
|
|
|
|
|
if index != -1 {
|
2022-08-02 10:58:30 -05:00
|
|
|
imageConfigInfo, err := olu.GetImageConfigInfo(repo, manifests[i].Digest)
|
2022-07-19 08:16:15 -05:00
|
|
|
if err != nil {
|
2022-08-02 10:58:30 -05:00
|
|
|
log.Error().Err(err).Msgf("can't retrieve config info for the image %s %s", repo, manifestTag)
|
2022-07-19 08:16:15 -05:00
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-07-12 07:58:04 -05:00
|
|
|
size := strconv.Itoa(int(imageSize))
|
2022-08-02 10:58:30 -05:00
|
|
|
isSigned := olu.CheckManifestSignature(repo, manifests[i].Digest)
|
2022-07-19 08:16:15 -05:00
|
|
|
|
2022-07-12 07:58:04 -05:00
|
|
|
// update matching score
|
|
|
|
score := calculateImageMatchingScore(repo, index, matchesTag)
|
|
|
|
|
2022-07-19 08:16:15 -05:00
|
|
|
vendor := olu.GetImageVendor(imageConfigInfo)
|
|
|
|
lastUpdated := olu.GetImageLastUpdated(imageConfigInfo)
|
|
|
|
os, arch := olu.GetImagePlatform(imageConfigInfo)
|
2022-07-12 07:58:04 -05:00
|
|
|
osArch := &gql_generated.OsArch{
|
|
|
|
Os: &os,
|
|
|
|
Arch: &arch,
|
|
|
|
}
|
|
|
|
|
|
|
|
repoPlatforms = append(repoPlatforms, osArch)
|
|
|
|
repoVendors = append(repoVendors, &vendor)
|
|
|
|
|
2022-07-22 15:01:38 -05:00
|
|
|
imageSummary := gql_generated.ImageSummary{
|
2022-07-12 07:58:04 -05:00
|
|
|
RepoName: &repo,
|
2022-08-02 10:58:30 -05:00
|
|
|
Tag: &manifestTag,
|
2022-07-12 07:58:04 -05:00
|
|
|
LastUpdated: &lastUpdated,
|
|
|
|
IsSigned: &isSigned,
|
|
|
|
Size: &size,
|
|
|
|
Platform: osArch,
|
|
|
|
Vendor: &vendor,
|
|
|
|
Score: &score,
|
2022-07-22 15:01:38 -05:00
|
|
|
}
|
|
|
|
|
2022-08-02 10:58:30 -05:00
|
|
|
if manifests[i].Digest.String() == lastUpdatedTag.Digest {
|
2022-07-22 15:01:38 -05:00
|
|
|
lastUpdatedImageSummary = imageSummary
|
|
|
|
}
|
|
|
|
|
|
|
|
images = append(images, &imageSummary)
|
2022-07-12 07:58:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-20 04:30:34 -05:00
|
|
|
for blob := range repoBlob2Size {
|
|
|
|
repoSize += repoBlob2Size[blob]
|
2022-07-12 07:58:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if index := strings.Index(repo, name); index != -1 {
|
|
|
|
repoSize := strconv.FormatInt(repoSize, 10)
|
|
|
|
|
|
|
|
repos = append(repos, &gql_generated.RepoSummary{
|
|
|
|
Name: &repo,
|
2022-07-22 15:01:38 -05:00
|
|
|
LastUpdated: &lastUpdatedTag.Timestamp,
|
2022-07-12 07:58:04 -05:00
|
|
|
Size: &repoSize,
|
|
|
|
Platforms: repoPlatforms,
|
|
|
|
Vendors: repoVendors,
|
|
|
|
Score: &index,
|
2022-01-19 10:57:10 -05:00
|
|
|
NewestImage: &lastUpdatedImageSummary,
|
2022-07-12 07:58:04 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(repos, func(i, j int) bool {
|
|
|
|
return *repos[i].Score < *repos[j].Score
|
|
|
|
})
|
|
|
|
|
|
|
|
sort.Slice(images, func(i, j int) bool {
|
|
|
|
return *images[i].Score < *images[j].Score
|
|
|
|
})
|
|
|
|
|
|
|
|
sort.Slice(layers, func(i, j int) bool {
|
|
|
|
return *layers[i].Score < *layers[j].Score
|
|
|
|
})
|
|
|
|
|
|
|
|
return repos, images, layers
|
|
|
|
}
|
|
|
|
|
|
|
|
// calcalculateImageMatchingScore iterated from the index of the matched string in the
|
|
|
|
// artifact name until the beginning of the string or until delimitator "/".
|
|
|
|
// The distance represents the score of the match.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
// query: image
|
|
|
|
// repos: repo/test/myimage
|
|
|
|
// Score will be 2.
|
|
|
|
func calculateImageMatchingScore(artefactName string, index int, matchesTag bool) int {
|
|
|
|
score := 0
|
|
|
|
|
|
|
|
for index >= 1 {
|
|
|
|
if artefactName[index-1] == '/' {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
index--
|
|
|
|
score++
|
|
|
|
}
|
|
|
|
|
|
|
|
if !matchesTag {
|
|
|
|
score += 10
|
|
|
|
}
|
|
|
|
|
|
|
|
return score
|
|
|
|
}
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
func (r *queryResolver) getImageList(store storage.ImageStore, imageName string) (
|
|
|
|
[]*gql_generated.ImageSummary, error,
|
|
|
|
) {
|
|
|
|
results := make([]*gql_generated.ImageSummary, 0)
|
|
|
|
|
|
|
|
repoList, err := store.GetRepositories()
|
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error extracting repositories list")
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
layoutUtils := common.NewBaseOciLayoutUtils(r.storeController, r.log)
|
|
|
|
|
|
|
|
for _, repo := range repoList {
|
|
|
|
if (imageName != "" && repo == imageName) || imageName == "" {
|
|
|
|
tagsInfo, err := layoutUtils.GetImageTagsWithTimestamp(repo)
|
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error getting tag timestamp info")
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(tagsInfo) == 0 {
|
|
|
|
r.log.Info().Str("no tagsinfo found for repo", repo).Msg(" continuing traversing")
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range tagsInfo {
|
|
|
|
// using a loop variable called tag would be reassigned after each iteration, using the same memory address
|
|
|
|
// directly access the value at the current index in the slice as ImageInfo requires pointers to tag fields
|
|
|
|
tag := tagsInfo[i]
|
|
|
|
|
|
|
|
digest := godigest.Digest(tag.Digest)
|
|
|
|
|
|
|
|
manifest, err := layoutUtils.GetImageBlobManifest(repo, digest)
|
|
|
|
if err != nil {
|
|
|
|
r.log.Error().Err(err).Msg("extension api: error reading manifest")
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
imageInfo := buildImageInfo(repo, tag.Name, digest, manifest)
|
|
|
|
|
|
|
|
results = append(results, imageInfo)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(results) == 0 {
|
|
|
|
r.log.Info().Msg("no repositories found")
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildImageInfo(repo string, tag string, tagDigest godigest.Digest,
|
|
|
|
manifest v1.Manifest,
|
|
|
|
) *gql_generated.ImageSummary {
|
|
|
|
layers := []*gql_generated.LayerSummary{}
|
|
|
|
size := int64(0)
|
|
|
|
|
|
|
|
for _, entry := range manifest.Layers {
|
|
|
|
size += entry.Size
|
|
|
|
digest := entry.Digest.Hex
|
|
|
|
layerSize := strconv.FormatInt(entry.Size, 10)
|
|
|
|
|
|
|
|
layers = append(
|
|
|
|
layers,
|
|
|
|
&gql_generated.LayerSummary{
|
|
|
|
Size: &layerSize,
|
|
|
|
Digest: &digest,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2020-08-19 01:53:04 -05:00
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
formattedSize := strconv.FormatInt(size, 10)
|
|
|
|
formattedTagDigest := tagDigest.Hex()
|
2020-08-19 01:53:04 -05:00
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
imageInfo := &gql_generated.ImageSummary{
|
|
|
|
RepoName: &repo,
|
|
|
|
Tag: &tag,
|
|
|
|
Digest: &formattedTagDigest,
|
|
|
|
ConfigDigest: &manifest.Config.Digest.Hex,
|
|
|
|
Size: &formattedSize,
|
|
|
|
Layers: layers,
|
2020-09-04 15:16:15 -05:00
|
|
|
}
|
|
|
|
|
2022-01-19 10:57:10 -05:00
|
|
|
return imageInfo
|
2020-08-19 01:53:04 -05:00
|
|
|
}
|