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:
parent
ae73290929
commit
0c70ae8a4e
6 changed files with 192 additions and 1 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -52,6 +52,7 @@ type ImageInfo {
|
||||||
|
|
||||||
type RepoInfo {
|
type RepoInfo {
|
||||||
Manifests: [ManifestInfo]
|
Manifests: [ManifestInfo]
|
||||||
|
Summary: RepoSummary
|
||||||
}
|
}
|
||||||
|
|
||||||
type ManifestInfo {
|
type ManifestInfo {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue