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

RepoInfo structure now includes new field representing RepoSummary

ExpandedRepoInfo currently returns RepoInfo that is a list of Manifests.
To comply with the newest UI requirements, a new field called Summary,
referring to RepoSummary structure, was added.

Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro>
This commit is contained in:
Alex Stan 2022-07-29 17:51:10 +03:00 committed by Andrei Aaron
parent ae73290929
commit 0c70ae8a4e
6 changed files with 192 additions and 1 deletions

View file

@ -517,7 +517,7 @@ func TestExpandedRepoInfo(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 422) So(resp.StatusCode(), ShouldEqual, 422)
query := "{ExpandedRepoInfo(repo:\"zot-cve-test\"){Manifests%20{Digest%20IsSigned%20Tag%20Layers%20{Size%20Digest}}}}" query := "{ExpandedRepoInfo(repo:\"zot-cve-test\"){Summary%20{Name%20LastUpdated%20Size%20Platforms%20{Os%20Arch}%20Vendors%20Score}}}" // nolint: lll
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query) resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query)
So(resp, ShouldNotBeNil) So(resp, ShouldNotBeNil)
@ -526,6 +526,21 @@ func TestExpandedRepoInfo(t *testing.T) {
responseStruct := &ExpandedRepoInfoResp{} responseStruct := &ExpandedRepoInfoResp{}
err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(responseStruct.ExpandedRepoInfo.RepoInfo.Summary, ShouldNotBeEmpty)
So(responseStruct.ExpandedRepoInfo.RepoInfo.Summary.Name, ShouldEqual, "zot-cve-test")
So(responseStruct.ExpandedRepoInfo.RepoInfo.Summary.Score, ShouldEqual, -1)
query = "{ExpandedRepoInfo(repo:\"zot-cve-test\"){Manifests%20{Digest%20IsSigned%20Tag%20Layers%20{Size%20Digest}}}}"
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query)
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
responseStruct = &ExpandedRepoInfoResp{}
err = json.Unmarshal(resp.Body(), responseStruct) err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(responseStruct.ExpandedRepoInfo.RepoInfo.Manifests), ShouldNotEqual, 0) So(len(responseStruct.ExpandedRepoInfo.RepoInfo.Manifests), ShouldNotEqual, 0)

View file

@ -43,6 +43,7 @@ type BaseOciLayoutUtils struct {
type RepoInfo struct { type RepoInfo struct {
Manifests []Manifest `json:"manifests"` Manifests []Manifest `json:"manifests"`
Summary RepoSummary
} }
type Manifest struct { type Manifest struct {
@ -52,6 +53,20 @@ type Manifest struct {
Layers []Layer `json:"layers"` Layers []Layer `json:"layers"`
} }
type RepoSummary struct {
Name string `json:"name"`
LastUpdated time.Time `json:"lastUpdated"`
Size string `json:"size"`
Platforms []OsArch `json:"platforms"`
Vendors []string `json:"vendors"`
Score int `json:"score"`
}
type OsArch struct {
Os string `json:"os"`
Arch string `json:"arch"`
}
type Layer struct { type Layer struct {
Size string `json:"size"` Size string `json:"size"`
Digest string `json:"digest"` Digest string `json:"digest"`
@ -337,8 +352,18 @@ func (olu BaseOciLayoutUtils) GetRepoLastUpdated(repo string) (TagInfo, error) {
func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error) { func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error) {
repo := RepoInfo{} repo := RepoInfo{}
repoBlob2Size := make(map[string]int64, 10)
// made up of all manifests, configs and image layers
repoSize := int64(0)
manifests := make([]Manifest, 0) manifests := make([]Manifest, 0)
tagsInfo, err := olu.GetImageTagsWithTimestamp(name)
if err != nil {
olu.Log.Error().Err(err).Msgf("can't get tags info for repo: %s", name)
}
manifestList, err := olu.GetImageManifests(name) manifestList, err := olu.GetImageManifests(name)
if err != nil { if err != nil {
olu.Log.Error().Err(err).Msg("error getting image manifests") olu.Log.Error().Err(err).Msg("error getting image manifests")
@ -346,6 +371,9 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error)
return RepoInfo{}, err return RepoInfo{}, err
} }
repoPlatforms := make([]OsArch, 0, len(tagsInfo))
repoVendors := make([]string, 0, len(manifestList))
for _, man := range manifestList { for _, man := range manifestList {
manifestInfo := Manifest{} manifestInfo := Manifest{}
@ -369,6 +397,30 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error)
manifestInfo.IsSigned = olu.checkManifestSignature(name, man.Digest) manifestInfo.IsSigned = olu.checkManifestSignature(name, man.Digest)
manifestSize := olu.GetImageManifestSize(name, man.Digest)
olu.Log.Debug().Msg(fmt.Sprintf("%v", man.Digest))
configSize := manifest.Config.Size
repoBlob2Size[man.Digest.String()] = manifestSize
repoBlob2Size[manifest.Config.Digest.Hex] = configSize
imageConfigInfo, err := olu.GetImageConfigInfo(name, man.Digest)
if err != nil {
olu.Log.Error().Err(err).Msgf("can't retrieve config info for the image %s %s", name, man.Digest)
continue
}
vendor := olu.GetImageVendor(imageConfigInfo)
os, arch := olu.GetImagePlatform(imageConfigInfo)
osArch := OsArch{
Os: os,
Arch: arch,
}
repoPlatforms = append(repoPlatforms, osArch)
repoVendors = append(repoVendors, vendor)
layers := make([]Layer, 0) layers := make([]Layer, 0)
for _, layer := range manifest.Layers { for _, layer := range manifest.Layers {
@ -376,6 +428,8 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error)
layerInfo.Digest = layer.Digest.Hex layerInfo.Digest = layer.Digest.Hex
repoBlob2Size[layerInfo.Digest] = layer.Size
layerInfo.Size = strconv.FormatInt(layer.Size, 10) layerInfo.Size = strconv.FormatInt(layer.Size, 10)
layers = append(layers, layerInfo) layers = append(layers, layerInfo)
@ -388,6 +442,28 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error)
repo.Manifests = manifests repo.Manifests = manifests
lastUpdate, err := olu.GetRepoLastUpdated(name)
if err != nil {
olu.Log.Error().Err(err).Msgf("can't find latest update timestamp for repo: %s", name)
}
for blob := range repoBlob2Size {
repoSize += repoBlob2Size[blob]
}
size := strconv.FormatInt(repoSize, 10)
summary := RepoSummary{
Name: name,
LastUpdated: lastUpdate.Timestamp,
Size: size,
Platforms: repoPlatforms,
Vendors: repoVendors,
Score: -1,
}
repo.Summary = summary
return repo, nil return repo, nil
} }

View file

@ -138,6 +138,7 @@ type ComplexityRoot struct {
RepoInfo struct { RepoInfo struct {
Manifests func(childComplexity int) int Manifests func(childComplexity int) int
Summary func(childComplexity int) int
} }
RepoSummary struct { RepoSummary struct {
@ -583,6 +584,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.RepoInfo.Manifests(childComplexity), true return e.complexity.RepoInfo.Manifests(childComplexity), true
case "RepoInfo.Summary":
if e.complexity.RepoInfo.Summary == nil {
break
}
return e.complexity.RepoInfo.Summary(childComplexity), true
case "RepoSummary.LastUpdated": case "RepoSummary.LastUpdated":
if e.complexity.RepoSummary.LastUpdated == nil { if e.complexity.RepoSummary.LastUpdated == nil {
break break
@ -759,6 +767,7 @@ type ImageInfo {
type RepoInfo { type RepoInfo {
Manifests: [ManifestInfo] Manifests: [ManifestInfo]
Summary: RepoSummary
} }
type ManifestInfo { type ManifestInfo {
@ -3241,6 +3250,8 @@ func (ec *executionContext) fieldContext_Query_ExpandedRepoInfo(ctx context.Cont
switch field.Name { switch field.Name {
case "Manifests": case "Manifests":
return ec.fieldContext_RepoInfo_Manifests(ctx, field) return ec.fieldContext_RepoInfo_Manifests(ctx, field)
case "Summary":
return ec.fieldContext_RepoInfo_Summary(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type RepoInfo", field.Name) return nil, fmt.Errorf("no field named %q was found under type RepoInfo", field.Name)
}, },
@ -3499,6 +3510,63 @@ func (ec *executionContext) fieldContext_RepoInfo_Manifests(ctx context.Context,
return fc, nil return fc, nil
} }
func (ec *executionContext) _RepoInfo_Summary(ctx context.Context, field graphql.CollectedField, obj *RepoInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_RepoInfo_Summary(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Summary, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*RepoSummary)
fc.Result = res
return ec.marshalORepoSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummary(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_RepoInfo_Summary(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "RepoInfo",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "Name":
return ec.fieldContext_RepoSummary_Name(ctx, field)
case "LastUpdated":
return ec.fieldContext_RepoSummary_LastUpdated(ctx, field)
case "Size":
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_RepoSummary_Score(ctx, field)
case "NewestTag":
return ec.fieldContext_RepoSummary_NewestTag(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type RepoSummary", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _RepoSummary_Name(ctx context.Context, field graphql.CollectedField, obj *RepoSummary) (ret graphql.Marshaler) { func (ec *executionContext) _RepoSummary_Name(ctx context.Context, field graphql.CollectedField, obj *RepoSummary) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_RepoSummary_Name(ctx, field) fc, err := ec.fieldContext_RepoSummary_Name(ctx, field)
if err != nil { if err != nil {
@ -6363,6 +6431,10 @@ func (ec *executionContext) _RepoInfo(ctx context.Context, sel ast.SelectionSet,
out.Values[i] = ec._RepoInfo_Manifests(ctx, field, obj) out.Values[i] = ec._RepoInfo_Manifests(ctx, field, obj)
case "Summary":
out.Values[i] = ec._RepoInfo_Summary(ctx, field, obj)
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }

View file

@ -92,6 +92,7 @@ type PackageInfo struct {
type RepoInfo struct { type RepoInfo struct {
Manifests []*ManifestInfo `json:"Manifests"` Manifests []*ManifestInfo `json:"Manifests"`
Summary *RepoSummary `json:"Summary"`
} }
type RepoSummary struct { type RepoSummary struct {

View file

@ -52,6 +52,7 @@ type ImageInfo {
type RepoInfo { type RepoInfo {
Manifests: [ManifestInfo] Manifests: [ManifestInfo]
Summary: RepoSummary
} }
type ManifestInfo { type ManifestInfo {

View file

@ -333,6 +333,31 @@ func (r *queryResolver) ExpandedRepoInfo(ctx context.Context, repo string) (*gql
manifests := make([]*gql_generated.ManifestInfo, 0) manifests := make([]*gql_generated.ManifestInfo, 0)
summary := &gql_generated.RepoSummary{}
summary.LastUpdated = &origRepoInfo.Summary.LastUpdated
summary.Name = &origRepoInfo.Summary.Name
summary.Platforms = []*gql_generated.OsArch{}
for _, platform := range origRepoInfo.Summary.Platforms {
platform := platform
summary.Platforms = append(summary.Platforms, &gql_generated.OsArch{
Os: &platform.Os,
Arch: &platform.Arch,
})
}
summary.Size = &origRepoInfo.Summary.Size
for _, vendor := range origRepoInfo.Summary.Vendors {
vendor := vendor
summary.Vendors = append(summary.Vendors, &vendor)
}
score := -1 // score not relevant for this query
summary.Score = &score
for _, manifest := range origRepoInfo.Manifests { for _, manifest := range origRepoInfo.Manifests {
tag := manifest.Tag tag := manifest.Tag
@ -359,6 +384,7 @@ func (r *queryResolver) ExpandedRepoInfo(ctx context.Context, repo string) (*gql
manifests = append(manifests, manifestInfo) manifests = append(manifests, manifestInfo)
} }
repoInfo.Summary = summary
repoInfo.Manifests = manifests repoInfo.Manifests = manifests
return repoInfo, nil return repoInfo, nil