mirror of
https://github.com/project-zot/zot.git
synced 2026-06-15 20:07:55 +08:00
freeform querry api
Signed-off-by: Laurentiu Niculae <themelopeus@gmail.com>
This commit is contained in:
committed by
Ramkumar Chinchani
parent
a31869f270
commit
7e3d063319
@@ -5,7 +5,9 @@ package search
|
||||
// It serves as dependency injection for your app, add any dependencies you require here.
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"zotregistry.io/zot/pkg/log" // nolint: gci
|
||||
@@ -123,7 +125,7 @@ func (r *queryResolver) getImageListWithLatestTag(store storage.ImageStore) ([]*
|
||||
r.log.Info().Msg("no repositories found")
|
||||
}
|
||||
|
||||
layoutUtils := common.NewOciLayoutUtils(r.storeController, r.log)
|
||||
layoutUtils := common.NewBaseOciLayoutUtils(r.storeController, r.log)
|
||||
|
||||
for _, repo := range repoList {
|
||||
tagsInfo, err := layoutUtils.GetImageTagsWithTimestamp(repo)
|
||||
@@ -186,6 +188,180 @@ func (r *queryResolver) getImageListWithLatestTag(store storage.ImageStore) ([]*
|
||||
return results, nil
|
||||
}
|
||||
|
||||
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
|
||||
repoLayerBlob2Size := make(map[string]int64, 10)
|
||||
|
||||
// made up of all manifests, configs and image layers
|
||||
repoSize := int64(0)
|
||||
|
||||
lastUpdate, err := olu.GetRepoLastUpdated(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("can't find latest update timestamp for repo: %s", repo)
|
||||
}
|
||||
|
||||
tagsInfo, err := olu.GetImageTagsWithTimestamp(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("can't get tags info for repo: %s", repo)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
repoInfo, err := olu.GetExpandedRepoInfo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("can't get repo info for repo: %s", repo)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
repoPlatforms := make([]*gql_generated.OsArch, 0, len(tagsInfo))
|
||||
repoVendors := make([]*string, 0, len(repoInfo.Manifests))
|
||||
|
||||
for i, manifest := range repoInfo.Manifests {
|
||||
imageLayersSize := int64(0)
|
||||
manifestSize := olu.GetImageManifestSize(repo, godigest.Digest(tagsInfo[i].Digest))
|
||||
configSize := olu.GetImageConfigSize(repo, godigest.Digest(tagsInfo[i].Digest))
|
||||
|
||||
for _, layer := range manifest.Layers {
|
||||
layer := layer
|
||||
|
||||
layerSize, err := strconv.ParseInt(layer.Size, 10, 64)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("invalid layer size")
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
repoLayerBlob2Size[layer.Digest] = layerSize
|
||||
imageLayersSize += layerSize
|
||||
|
||||
// if we have a tag we won't match a layer
|
||||
if tag != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if index := strings.Index(layer.Digest, name); index != -1 {
|
||||
layers = append(layers, &gql_generated.LayerSummary{
|
||||
Digest: &layer.Digest,
|
||||
Size: &layer.Size,
|
||||
Score: &index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
imageSize := imageLayersSize + manifestSize + configSize
|
||||
repoSize += manifestSize + configSize
|
||||
|
||||
index := strings.Index(repo, name)
|
||||
matchesTag := strings.HasPrefix(manifest.Tag, tag)
|
||||
|
||||
if index != -1 {
|
||||
tag := manifest.Tag
|
||||
size := strconv.Itoa(int(imageSize))
|
||||
vendor := olu.GetImageVendor(repo, godigest.Digest(tagsInfo[i].Digest))
|
||||
lastUpdated := olu.GetImageLastUpdated(repo, godigest.Digest(tagsInfo[i].Digest))
|
||||
|
||||
isSigned := manifest.IsSigned
|
||||
// update matching score
|
||||
score := calculateImageMatchingScore(repo, index, matchesTag)
|
||||
|
||||
os, arch := olu.GetImagePlatform(repo, godigest.Digest(tagsInfo[i].Digest))
|
||||
osArch := &gql_generated.OsArch{
|
||||
Os: &os,
|
||||
Arch: &arch,
|
||||
}
|
||||
|
||||
repoPlatforms = append(repoPlatforms, osArch)
|
||||
repoVendors = append(repoVendors, &vendor)
|
||||
|
||||
images = append(images, &gql_generated.ImageSummary{
|
||||
RepoName: &repo,
|
||||
Tag: &tag,
|
||||
LastUpdated: &lastUpdated,
|
||||
IsSigned: &isSigned,
|
||||
Size: &size,
|
||||
Platform: osArch,
|
||||
Vendor: &vendor,
|
||||
Score: &score,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for layerBlob := range repoLayerBlob2Size {
|
||||
repoSize += repoLayerBlob2Size[layerBlob]
|
||||
}
|
||||
|
||||
if index := strings.Index(repo, name); index != -1 {
|
||||
repoSize := strconv.FormatInt(repoSize, 10)
|
||||
|
||||
repos = append(repos, &gql_generated.RepoSummary{
|
||||
Name: &repo,
|
||||
LastUpdated: &lastUpdate,
|
||||
Size: &repoSize,
|
||||
Platforms: repoPlatforms,
|
||||
Vendors: repoVendors,
|
||||
Score: &index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func getGraphqlCompatibleTags(fixedTags []common.TagInfo) []*gql_generated.TagInfo {
|
||||
finalTagList := make([]*gql_generated.TagInfo, 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user