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:
parent
981ca6ddb4
commit
9ca5fa1029
5 changed files with 361 additions and 132 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue