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,9 +52,9 @@ var (
subRootDir string
)
type ImgResponsWithLatestTag struct {
ImgListWithLatestTag ImgListWithLatestTag `json:"data"`
Errors []ErrorGQL `json:"errors"`
type RepoWithNewestImageResponse struct {
RepoListWithNewestImage RepoListWithNewestImage `json:"data"`
Errors []ErrorGQL `json:"errors"`
}
type ExpandedRepoInfoResp struct {
@ -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

@ -98,14 +98,14 @@ type ComplexityRoot struct {
}
Query struct {
CVEListForImage func(childComplexity int, image string) int
ExpandedRepoInfo func(childComplexity int, repo string) int
GlobalSearch func(childComplexity int, query string) int
ImageList func(childComplexity int, repo string) int
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
CVEListForImage func(childComplexity int, image string) int
ExpandedRepoInfo func(childComplexity int, repo string) int
GlobalSearch func(childComplexity int, query string) int
ImageList func(childComplexity int, repo string) int
ImageListForCve func(childComplexity int, id string) int
ImageListForDigest func(childComplexity int, id string) int
ImageListWithCVEFixed func(childComplexity int, id string, image string) 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
}
imageSize := imageLayersSize + manifestSize + configSize
imageConfigInfo, _ := olu.GetImageConfigInfo(repo, manifests[i].Digest)
os, arch := olu.GetImagePlatform(imageConfigInfo)
osArch := &gql_generated.OsArch{
Os: &os,
Arch: &arch,
}
repoPlatforms = append(repoPlatforms, osArch)
vendor := olu.GetImageVendor(imageConfigInfo)
repoVendors = append(repoVendors, &vendor)
manifestTag, ok := manifest.Annotations[ispec.AnnotationRefName]
if !ok {
graphql.AddError(ctx, gqlerror.Errorf("reference not found for this manifest"))
brokenManifest = true
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
}
}
labels := imageConfig.Config.Labels
if brokenManifest {
continue
}
// Read Description
desc := common.GetDescription(labels)
for blob := range repoBlob2Size {
repoSize += repoBlob2Size[blob]
}
// Read licenses
license := common.GetLicense(labels)
repoSizeStr := strconv.FormatInt(repoSize, 10)
index := 0
// Read vendor
vendor := common.GetVendor(labels)
// Read categories
categories := common.GetCategories(labels)
results = append(results, &gql_generated.ImageSummary{
RepoName: &name, Tag: &latestTag.Name,
Description: &desc, Licenses: &license, Vendor: &vendor,
Labels: &categories, Size: &size, LastUpdated: &latestTag.Timestamp,
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.