0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-30 22:34:13 -05:00

Implement RepoListWithNewestImage to return [RepoSummary]

Removed access by index in repoListWithNewestImage

Signed-off-by: Catalin Hofnar <catalin.hofnar@gmail.com>
This commit is contained in:
Catalin Hofnar 2022-07-29 18:33:34 +03:00 committed by Andrei Aaron
parent 981ca6ddb4
commit 9ca5fa1029
5 changed files with 361 additions and 132 deletions

View file

@ -24,6 +24,7 @@ import (
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/resty.v1"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/api/constants"
@ -51,8 +52,8 @@ var (
subRootDir string
)
type ImgResponsWithLatestTag struct {
ImgListWithLatestTag ImgListWithLatestTag `json:"data"`
type RepoWithNewestImageResponse struct {
RepoListWithNewestImage RepoListWithNewestImage `json:"data"`
Errors []ErrorGQL `json:"errors"`
}
@ -112,8 +113,8 @@ type ExpandedRepoInfo struct {
}
//nolint:tagliatelle // graphQL schema
type ImgListWithLatestTag struct {
Images []ImageInfo `json:"ImageListWithLatestTag"`
type RepoListWithNewestImage struct {
Repos []RepoSummary `json:"RepoListWithNewestImage"`
}
type ErrorGQL struct {
@ -318,8 +319,132 @@ func TestImageFormat(t *testing.T) {
})
}
func TestLatestTagSearchHTTP(t *testing.T) {
Convey("Test latest image search by timestamp", t, func() {
func TestRepoListWithNewestImage(t *testing.T) {
Convey("Test repoListWithNewestImage AddError", t, func() {
subpath := "/a"
err := testSetup(t, subpath)
if err != nil {
panic(err)
}
err = os.RemoveAll(path.Join(rootDir, "zot-cve-test"))
if err != nil {
panic(err)
}
err = os.RemoveAll(path.Join(rootDir, subpath))
if err != nil {
panic(err)
}
port := GetFreePort()
baseURL := GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = rootDir
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{Enable: &defaultVal},
}
conf.Extensions.Search.CVE = nil
ctlr := api.NewController(conf)
go func() {
// this blocks
if err := ctlr.Run(context.Background()); err != nil {
return
}
}()
// wait till ready
for {
_, err := resty.R().Get(baseURL)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
// shut down server
defer func() {
ctx := context.Background()
_ = ctlr.Server.Shutdown(ctx)
}()
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = os.Remove(path.Join(rootDir,
"zot-test/blobs/sha256/2bacca16b9df395fc855c14ccf50b12b58d35d468b8e7f25758aff90f89bf396"))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
errmsg := fmt.Sprint(zerr.ErrBlobNotFound)
body := string(resp.Body())
So(body, ShouldContainSubstring, errmsg)
So(resp.StatusCode(), ShouldEqual, 200)
err = CopyFiles("../../../../test/data/zot-test", path.Join(rootDir, "zot-test"))
if err != nil {
panic(err)
}
err = os.Remove(path.Join(rootDir,
"zot-test/blobs/sha256/adf3bb6cc81f8bd6a9d5233be5f0c1a4f1e3ed1cf5bbdfad7708cc8d4099b741"))
if err != nil {
panic(err)
}
err = os.Remove(path.Join(rootDir,
"zot-test/blobs/sha256/2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc"))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
errmsg = fmt.Sprint(zerr.ErrBlobNotFound)
body = string(resp.Body())
So(body, ShouldContainSubstring, errmsg)
So(resp.StatusCode(), ShouldEqual, 200)
err = CopyFiles("../../../../test/data/zot-test", path.Join(rootDir, "zot-test"))
if err != nil {
panic(err)
}
err = os.Remove(path.Join(rootDir, "zot-test/index.json"))
if err != nil {
panic(err)
}
//nolint: lll
manifestNoAnnotations := "{\"schemaVersion\":2,\"manifests\":[{\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"digest\":\"sha256:2bacca16b9df395fc855c14ccf50b12b58d35d468b8e7f25758aff90f89bf396\",\"size\":350}]}"
err = os.WriteFile(path.Join(rootDir, "zot-test/index.json"), []byte(manifestNoAnnotations), 0o600)
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
body = string(resp.Body())
So(body, ShouldContainSubstring, "reference not found for this manifest")
So(resp.StatusCode(), ShouldEqual, 200)
})
Convey("Test repoListWithNewestImage by tag with HTTP", t, func() {
subpath := "/a"
err := testSetup(t, subpath)
if err != nil {
@ -373,20 +498,22 @@ func TestLatestTagSearchHTTP(t *testing.T) {
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 422)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
var responseStruct ImgResponsWithLatestTag
var responseStruct RepoWithNewestImageResponse
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.ImgListWithLatestTag.Images), ShouldEqual, 4)
So(len(responseStruct.RepoListWithNewestImage.Repos), ShouldEqual, 4)
images := responseStruct.ImgListWithLatestTag.Images
So(images[0].Tag, ShouldEqual, "0.0.1")
images := responseStruct.RepoListWithNewestImage.Repos
So(images[0].NewestImage.Tag, ShouldEqual, "0.0.1")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
@ -395,14 +522,15 @@ func TestLatestTagSearchHTTP(t *testing.T) {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.ImgListWithLatestTag.Images), ShouldEqual, 0)
So(responseStruct.Errors, ShouldNotBeNil)
err = os.Chmod(rootDir, 0o755)
if err != nil {
@ -419,7 +547,8 @@ func TestLatestTagSearchHTTP(t *testing.T) {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
@ -430,7 +559,8 @@ func TestLatestTagSearchHTTP(t *testing.T) {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
@ -440,7 +570,8 @@ func TestLatestTagSearchHTTP(t *testing.T) {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
@ -451,7 +582,8 @@ func TestLatestTagSearchHTTP(t *testing.T) {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){RepoName%20Tag}}")
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

View file

@ -105,7 +105,7 @@ type ComplexityRoot struct {
ImageListForCve func(childComplexity int, id string) int
ImageListForDigest func(childComplexity int, id string) int
ImageListWithCVEFixed func(childComplexity int, id string, image string) int
ImageListWithLatestTag func(childComplexity int) int
RepoListWithNewestImage func(childComplexity int) int
}
RepoInfo struct {
@ -132,7 +132,7 @@ type QueryResolver interface {
ImageListForCve(ctx context.Context, id string) ([]*ImageSummary, error)
ImageListWithCVEFixed(ctx context.Context, id string, image string) ([]*ImageSummary, error)
ImageListForDigest(ctx context.Context, id string) ([]*ImageSummary, error)
ImageListWithLatestTag(ctx context.Context) ([]*ImageSummary, error)
RepoListWithNewestImage(ctx context.Context) ([]*RepoSummary, error)
ImageList(ctx context.Context, repo string) ([]*ImageSummary, error)
ExpandedRepoInfo(ctx context.Context, repo string) (*RepoInfo, error)
GlobalSearch(ctx context.Context, query string) (*GlobalSearchResult, error)
@ -468,12 +468,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Query.ImageListWithCVEFixed(childComplexity, args["id"].(string), args["image"].(string)), true
case "Query.ImageListWithLatestTag":
if e.complexity.Query.ImageListWithLatestTag == nil {
case "Query.RepoListWithNewestImage":
if e.complexity.Query.RepoListWithNewestImage == nil {
break
}
return e.complexity.Query.ImageListWithLatestTag(childComplexity), true
return e.complexity.Query.RepoListWithNewestImage(childComplexity), true
case "RepoInfo.Images":
if e.complexity.RepoInfo.Images == nil {
@ -697,7 +697,7 @@ type Query {
ImageListForCVE(id: String!): [ImageSummary!]
ImageListWithCVEFixed(id: String!, image: String!): [ImageSummary!]
ImageListForDigest(id: String!): [ImageSummary!]
ImageListWithLatestTag: [ImageSummary!]
RepoListWithNewestImage: [RepoSummary!]! # Newest based on created timestamp
ImageList(repo: String!): [ImageSummary!]
ExpandedRepoInfo(repo: String!): RepoInfo!
GlobalSearch(query: String!): GlobalSearchResult!
@ -2639,8 +2639,8 @@ func (ec *executionContext) fieldContext_Query_ImageListForDigest(ctx context.Co
return fc, nil
}
func (ec *executionContext) _Query_ImageListWithLatestTag(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_ImageListWithLatestTag(ctx, field)
func (ec *executionContext) _Query_RepoListWithNewestImage(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_RepoListWithNewestImage(ctx, field)
if err != nil {
return graphql.Null
}
@ -2653,21 +2653,24 @@ func (ec *executionContext) _Query_ImageListWithLatestTag(ctx context.Context, f
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().ImageListWithLatestTag(rctx)
return ec.resolvers.Query().RepoListWithNewestImage(rctx)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]*ImageSummary)
res := resTmp.([]*RepoSummary)
fc.Result = res
return ec.marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx, field.Selections, res)
return ec.marshalNRepoSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummaryᚄ(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Query_ImageListWithLatestTag(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_Query_RepoListWithNewestImage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Query",
Field: field,
@ -2675,38 +2678,28 @@ func (ec *executionContext) fieldContext_Query_ImageListWithLatestTag(ctx contex
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "RepoName":
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
case "Tag":
return ec.fieldContext_ImageSummary_Tag(ctx, field)
case "Digest":
return ec.fieldContext_ImageSummary_Digest(ctx, field)
case "ConfigDigest":
return ec.fieldContext_ImageSummary_ConfigDigest(ctx, field)
case "Name":
return ec.fieldContext_RepoSummary_Name(ctx, field)
case "LastUpdated":
return ec.fieldContext_ImageSummary_LastUpdated(ctx, field)
case "IsSigned":
return ec.fieldContext_ImageSummary_IsSigned(ctx, field)
return ec.fieldContext_RepoSummary_LastUpdated(ctx, field)
case "Size":
return ec.fieldContext_ImageSummary_Size(ctx, field)
case "Platform":
return ec.fieldContext_ImageSummary_Platform(ctx, field)
case "Vendor":
return ec.fieldContext_ImageSummary_Vendor(ctx, field)
return ec.fieldContext_RepoSummary_Size(ctx, field)
case "Platforms":
return ec.fieldContext_RepoSummary_Platforms(ctx, field)
case "Vendors":
return ec.fieldContext_RepoSummary_Vendors(ctx, field)
case "Score":
return ec.fieldContext_ImageSummary_Score(ctx, field)
return ec.fieldContext_RepoSummary_Score(ctx, field)
case "NewestImage":
return ec.fieldContext_RepoSummary_NewestImage(ctx, field)
case "DownloadCount":
return ec.fieldContext_ImageSummary_DownloadCount(ctx, field)
case "Layers":
return ec.fieldContext_ImageSummary_Layers(ctx, field)
case "Description":
return ec.fieldContext_ImageSummary_Description(ctx, field)
case "Licenses":
return ec.fieldContext_ImageSummary_Licenses(ctx, field)
case "Labels":
return ec.fieldContext_ImageSummary_Labels(ctx, field)
return ec.fieldContext_RepoSummary_DownloadCount(ctx, field)
case "StarCount":
return ec.fieldContext_RepoSummary_StarCount(ctx, field)
case "IsBookmarked":
return ec.fieldContext_RepoSummary_IsBookmarked(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type ImageSummary", field.Name)
return nil, fmt.Errorf("no field named %q was found under type RepoSummary", field.Name)
},
}
return fc, nil
@ -5795,7 +5788,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
out.Concurrently(i, func() graphql.Marshaler {
return rrm(innerCtx)
})
case "ImageListWithLatestTag":
case "RepoListWithNewestImage":
field := field
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
@ -5804,7 +5797,10 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Query_ImageListWithLatestTag(ctx, field)
res = ec._Query_RepoListWithNewestImage(ctx, field)
if res == graphql.Null {
atomic.AddUint32(&invalids, 1)
}
return res
}
@ -6379,6 +6375,60 @@ func (ec *executionContext) marshalNRepoInfo2ᚖzotregistryᚗioᚋzotᚋpkgᚋe
return ec._RepoInfo(ctx, sel, v)
}
func (ec *executionContext) marshalNRepoSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummaryᚄ(ctx context.Context, sel ast.SelectionSet, v []*RepoSummary) graphql.Marshaler {
ret := make(graphql.Array, len(v))
var wg sync.WaitGroup
isLen1 := len(v) == 1
if !isLen1 {
wg.Add(len(v))
}
for i := range v {
i := i
fc := &graphql.FieldContext{
Index: &i,
Result: &v[i],
}
ctx := graphql.WithFieldContext(ctx, fc)
f := func(i int) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = nil
}
}()
if !isLen1 {
defer wg.Done()
}
ret[i] = ec.marshalNRepoSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummary(ctx, sel, v[i])
}
if isLen1 {
f(i)
} else {
go f(i)
}
}
wg.Wait()
for _, e := range ret {
if e == graphql.Null {
return graphql.Null
}
}
return ret
}
func (ec *executionContext) marshalNRepoSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummary(ctx context.Context, sel ast.SelectionSet, v *RepoSummary) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._RepoSummary(ctx, sel, v)
}
func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) {
res, err := graphql.UnmarshalString(v)
return res, graphql.ErrorOnPath(ctx, err)

View file

@ -11,10 +11,12 @@ import (
"strconv"
"strings"
glob "github.com/bmatcuk/doublestar/v4"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/99designs/gqlgen/graphql"
glob "github.com/bmatcuk/doublestar/v4" // nolint:gci
v1 "github.com/google/go-containerregistry/pkg/v1" // nolint:gci
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/vektah/gqlparser/v2/gqlerror"
"zotregistry.io/zot/pkg/extensions/search/common"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
digestinfo "zotregistry.io/zot/pkg/extensions/search/digest"
@ -114,80 +116,125 @@ func (r *queryResolver) getImageListForDigest(repoList []string, digest string)
return imgResultForDigest, errResult
}
func (r *queryResolver) getImageListWithLatestTag(store storage.ImageStore) ([]*gql_generated.ImageSummary, error) {
results := make([]*gql_generated.ImageSummary, 0)
// nolint:lll
func (r *queryResolver) repoListWithNewestImage(ctx context.Context, store storage.ImageStore) ([]*gql_generated.RepoSummary, error) {
repos := []*gql_generated.RepoSummary{}
olu := common.NewBaseOciLayoutUtils(r.storeController, r.log)
repoList, err := store.GetRepositories()
repoNames, err := store.GetRepositories()
if err != nil {
r.log.Error().Err(err).Msg("extension api: error extracting repositories list")
return results, err
return nil, err
}
if len(repoList) == 0 {
r.log.Info().Msg("no repositories found")
}
layoutUtils := common.NewBaseOciLayoutUtils(r.storeController, r.log)
for _, repo := range repoList {
tagsInfo, err := layoutUtils.GetImageTagsWithTimestamp(repo)
for _, repo := range repoNames {
lastUpdatedTag, err := olu.GetRepoLastUpdated(repo)
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")
graphql.AddError(ctx, err)
continue
}
latestTag := common.GetLatestTag(tagsInfo)
repoSize := int64(0)
repoBlob2Size := make(map[string]int64, 10)
tagsInfo, _ := olu.GetImageTagsWithTimestamp(repo)
digest := godigest.Digest(latestTag.Digest)
manifest, err := layoutUtils.GetImageBlobManifest(repo, digest)
manifests, err := olu.GetImageManifests(repo)
if err != nil {
r.log.Error().Err(err).Msg("extension api: error reading manifest")
graphql.AddError(ctx, err)
return results, err
continue
}
size := strconv.FormatInt(manifest.Config.Size, 10)
repoPlatforms := make([]*gql_generated.OsArch, 0, len(tagsInfo))
repoVendors := make([]*string, 0, len(manifests))
repoName := repo
name := repo
var lastUpdatedImageSummary gql_generated.ImageSummary
imageConfig, err := layoutUtils.GetImageInfo(repo, manifest.Config.Digest)
if err != nil {
r.log.Error().Err(err).Msg("extension api: error reading image config")
var brokenManifest bool
return results, err
for i, manifest := range manifests {
imageLayersSize := int64(0)
manifestSize := olu.GetImageManifestSize(repo, manifests[i].Digest)
imageBlobManifest, _ := olu.GetImageBlobManifest(repo, manifests[i].Digest)
configSize := imageBlobManifest.Config.Size
repoBlob2Size[manifests[i].Digest.String()] = manifestSize
repoBlob2Size[imageBlobManifest.Config.Digest.Hex] = configSize
for _, layer := range imageBlobManifest.Layers {
repoBlob2Size[layer.Digest.String()] = layer.Size
imageLayersSize += layer.Size
}
labels := imageConfig.Config.Labels
imageSize := imageLayersSize + manifestSize + configSize
// Read Description
desc := common.GetDescription(labels)
imageConfigInfo, _ := olu.GetImageConfigInfo(repo, manifests[i].Digest)
// Read licenses
license := common.GetLicense(labels)
os, arch := olu.GetImagePlatform(imageConfigInfo)
osArch := &gql_generated.OsArch{
Os: &os,
Arch: &arch,
}
repoPlatforms = append(repoPlatforms, osArch)
// Read vendor
vendor := common.GetVendor(labels)
vendor := olu.GetImageVendor(imageConfigInfo)
repoVendors = append(repoVendors, &vendor)
// Read categories
categories := common.GetCategories(labels)
manifestTag, ok := manifest.Annotations[ispec.AnnotationRefName]
if !ok {
graphql.AddError(ctx, gqlerror.Errorf("reference not found for this manifest"))
brokenManifest = true
results = append(results, &gql_generated.ImageSummary{
RepoName: &name, Tag: &latestTag.Name,
Description: &desc, Licenses: &license, Vendor: &vendor,
Labels: &categories, Size: &size, LastUpdated: &latestTag.Timestamp,
break
}
tag := manifestTag
size := strconv.Itoa(int(imageSize))
isSigned := olu.CheckManifestSignature(repo, manifests[i].Digest)
lastUpdated := olu.GetImageLastUpdated(imageConfigInfo)
score := 0
imageSummary := gql_generated.ImageSummary{
RepoName: &repoName,
Tag: &tag,
LastUpdated: &lastUpdated,
IsSigned: &isSigned,
Size: &size,
Platform: osArch,
Vendor: &vendor,
Score: &score,
}
if tagsInfo[i].Digest == lastUpdatedTag.Digest {
lastUpdatedImageSummary = imageSummary
}
}
if brokenManifest {
continue
}
for blob := range repoBlob2Size {
repoSize += repoBlob2Size[blob]
}
repoSizeStr := strconv.FormatInt(repoSize, 10)
index := 0
repos = append(repos, &gql_generated.RepoSummary{
Name: &repoName,
LastUpdated: &lastUpdatedTag.Timestamp,
Size: &repoSizeStr,
Platforms: repoPlatforms,
Vendors: repoVendors,
Score: &index,
NewestImage: &lastUpdatedImageSummary,
})
}
return results, nil
return repos, nil
}
func cleanQuerry(query string) string {

View file

@ -84,7 +84,7 @@ type Query {
ImageListForCVE(id: String!): [ImageSummary!]
ImageListWithCVEFixed(id: String!, image: String!): [ImageSummary!]
ImageListForDigest(id: String!): [ImageSummary!]
ImageListWithLatestTag: [ImageSummary!]
RepoListWithNewestImage: [RepoSummary!]! # Newest based on created timestamp
ImageList(repo: String!): [ImageSummary!]
ExpandedRepoInfo(repo: String!): RepoInfo!
GlobalSearch(query: String!): GlobalSearchResult!

View file

@ -287,41 +287,41 @@ func (r *queryResolver) ImageListForDigest(ctx context.Context, id string) ([]*g
return imgResultForDigest, nil
}
// ImageListWithLatestTag is the resolver for the ImageListWithLatestTag field.
func (r *queryResolver) ImageListWithLatestTag(ctx context.Context) ([]*gql_generated.ImageSummary, error) {
// RepoListWithNewestImage is the resolver for the RepoListWithNewestImage field.
func (r *queryResolver) RepoListWithNewestImage(ctx context.Context) ([]*gql_generated.RepoSummary, error) {
r.log.Info().Msg("extension api: finding image list")
imageList := make([]*gql_generated.ImageSummary, 0)
repoList := make([]*gql_generated.RepoSummary, 0)
defaultStore := r.storeController.DefaultStore
dsImageList, err := r.getImageListWithLatestTag(defaultStore)
dsRepoList, err := r.repoListWithNewestImage(ctx, defaultStore)
if err != nil {
r.log.Error().Err(err).Msg("extension api: error extracting default store image list")
return imageList, err
return repoList, err
}
if len(dsImageList) != 0 {
imageList = append(imageList, dsImageList...)
if len(dsRepoList) != 0 {
repoList = append(repoList, dsRepoList...)
}
subStore := r.storeController.SubStore
for _, store := range subStore {
ssImageList, err := r.getImageListWithLatestTag(store)
ssRepoList, err := r.repoListWithNewestImage(ctx, store)
if err != nil {
r.log.Error().Err(err).Msg("extension api: error extracting default store image list")
r.log.Error().Err(err).Msg("extension api: error extracting substore image list")
return imageList, err
return repoList, err
}
if len(ssImageList) != 0 {
imageList = append(imageList, ssImageList...)
if len(ssRepoList) != 0 {
repoList = append(repoList, ssRepoList...)
}
}
return imageList, nil
return repoList, nil
}
// ImageList is the resolver for the ImageList field.