diff --git a/pkg/meta/common/common.go b/pkg/meta/common/common.go index 4f07a06b..c787cc8f 100644 --- a/pkg/meta/common/common.go +++ b/pkg/meta/common/common.go @@ -270,3 +270,19 @@ func MatchesArtifactTypes(descriptorMediaType string, artifactTypes []string) bo return found } + +// CheckImageLastUpdated check if the given image is updated earlier than the current repoLastUpdated value +// +// It returns updated values for: repoLastUpdated, noImageChecked, isSigned. +func CheckImageLastUpdated(repoLastUpdated time.Time, isSigned bool, noImageChecked bool, + manifestFilterData repodb.FilterData, +) (time.Time, bool, bool) { + if noImageChecked || repoLastUpdated.Before(manifestFilterData.LastUpdated) { + repoLastUpdated = manifestFilterData.LastUpdated + noImageChecked = false + + isSigned = manifestFilterData.IsSigned + } + + return repoLastUpdated, noImageChecked, isSigned +} diff --git a/pkg/meta/common/common_test.go b/pkg/meta/common/common_test.go index db61bfcb..8f3e31e5 100644 --- a/pkg/meta/common/common_test.go +++ b/pkg/meta/common/common_test.go @@ -2,10 +2,12 @@ package common_test import ( "testing" + "time" . "github.com/smartystreets/goconvey/convey" "zotregistry.io/zot/pkg/meta/common" + "zotregistry.io/zot/pkg/meta/repodb" ) func TestUtils(t *testing.T) { @@ -21,4 +23,75 @@ func TestUtils(t *testing.T) { res = common.MatchesArtifactTypes("type", []string{"someOtherType"}) So(res, ShouldBeFalse) }) + + Convey("CheckImageLastUpdated", t, func() { + Convey("No image checked, it doesn't have time", func() { + repoLastUpdated := time.Time{} + isSigned := false + noImageChecked := true + manifestFilterData := repodb.FilterData{ + DownloadCount: 10, + LastUpdated: time.Time{}, + IsSigned: true, + } + + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, noImageChecked, + manifestFilterData) + So(repoLastUpdated, ShouldResemble, manifestFilterData.LastUpdated) + So(isSigned, ShouldEqual, manifestFilterData.IsSigned) + So(noImageChecked, ShouldEqual, false) + }) + + Convey("First image checked, it has time", func() { + repoLastUpdated := time.Time{} + isSigned := false + noImageChecked := true + manifestFilterData := repodb.FilterData{ + DownloadCount: 10, + LastUpdated: time.Date(2000, 1, 1, 1, 1, 1, 1, time.UTC), + IsSigned: true, + } + + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, noImageChecked, + manifestFilterData) + So(repoLastUpdated, ShouldResemble, manifestFilterData.LastUpdated) + So(isSigned, ShouldEqual, manifestFilterData.IsSigned) + So(noImageChecked, ShouldEqual, false) + }) + + Convey("Not first image checked, current image is newer", func() { + repoLastUpdated := time.Date(2000, 1, 1, 1, 1, 1, 1, time.UTC) + isSigned := true + noImageChecked := false + manifestFilterData := repodb.FilterData{ + DownloadCount: 10, + LastUpdated: time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC), + IsSigned: false, + } + + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, + noImageChecked, manifestFilterData) + So(repoLastUpdated, ShouldResemble, manifestFilterData.LastUpdated) + So(isSigned, ShouldEqual, manifestFilterData.IsSigned) + So(noImageChecked, ShouldEqual, false) + }) + + Convey("Not first image checked, current image is older", func() { + repoLastUpdated := time.Date(2024, 1, 1, 1, 1, 1, 1, time.UTC) + isSigned := false + noImageChecked := false + manifestFilterData := repodb.FilterData{ + DownloadCount: 10, + LastUpdated: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC), + IsSigned: true, + } + + updatedRepoLastUpdated, noImageChecked, isSigned := common.CheckImageLastUpdated(repoLastUpdated, isSigned, + noImageChecked, + manifestFilterData) + So(updatedRepoLastUpdated, ShouldResemble, repoLastUpdated) + So(isSigned, ShouldEqual, false) + So(noImageChecked, ShouldEqual, false) + }) + }) } diff --git a/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go b/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go index c8f28382..287dd7ec 100644 --- a/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go +++ b/pkg/meta/repodb/boltdb-wrapper/boltdb_wrapper.go @@ -908,12 +908,12 @@ func (bdw *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter if rank := common.RankRepoName(searchText, string(repoName)); rank != -1 { var ( // specific values used for sorting that need to be calculated based on all manifests from the repo - repoDownloads = 0 - repoLastUpdated time.Time - firstImageChecked = true - osSet = map[string]bool{} - archSet = map[string]bool{} - isSigned = false + repoDownloads = 0 + repoLastUpdated = time.Time{} + noImageChecked = true + osSet = map[string]bool{} + archSet = map[string]bool{} + isSigned = false ) for tag, descriptor := range repoMeta.Tags { @@ -943,17 +943,11 @@ func (bdw *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter archSet[arch] = true } - if firstImageChecked || repoLastUpdated.Before(manifestFilterData.LastUpdated) { - repoLastUpdated = manifestFilterData.LastUpdated - firstImageChecked = false - - isSigned = manifestFilterData.IsSigned - } + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, + noImageChecked, manifestFilterData) manifestMetadataMap[descriptor.Digest] = manifestMeta case ispec.MediaTypeImageIndex: - var indexLastUpdated time.Time - indexDigest := descriptor.Digest indexData, err := fetchIndexDataWithCheck(indexDigest, indexDataMap, indexBuck) @@ -971,28 +965,25 @@ func (bdw *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter } // this also updates manifestMetadataMap - imageFilterData, err := collectImageIndexFilterInfo(indexDigest, repoMeta, indexData, manifestMetadataMap, + indexFilterData, err := collectImageIndexFilterInfo(indexDigest, repoMeta, indexData, manifestMetadataMap, manifestBuck) if err != nil { return fmt.Errorf("repodb: error collecting filter data for index with digest %s %w", indexDigest, err) } - for _, arch := range imageFilterData.ArchList { + for _, arch := range indexFilterData.ArchList { archSet[arch] = true } - for _, os := range imageFilterData.OsList { + for _, os := range indexFilterData.OsList { osSet[os] = true } - repoDownloads += imageFilterData.DownloadCount + repoDownloads += indexFilterData.DownloadCount - if repoLastUpdated.Before(imageFilterData.LastUpdated) { - repoLastUpdated = indexLastUpdated - - isSigned = imageFilterData.IsSigned - } + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, + noImageChecked, indexFilterData) indexDataMap[indexDigest] = indexData default: @@ -1003,9 +994,11 @@ func (bdw *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter } repoFilterData := repodb.FilterData{ - OsList: common.GetMapKeys(osSet), - ArchList: common.GetMapKeys(archSet), - IsSigned: isSigned, + OsList: common.GetMapKeys(osSet), + ArchList: common.GetMapKeys(archSet), + LastUpdated: repoLastUpdated, + DownloadCount: repoDownloads, + IsSigned: isSigned, } if !common.AcceptedByFilter(filter, repoFilterData) { diff --git a/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go b/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go index 8fb4ad00..46585acd 100644 --- a/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go +++ b/pkg/meta/repodb/dynamodb-wrapper/dynamo_wrapper.go @@ -806,12 +806,12 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter if rank := common.RankRepoName(searchText, repoMeta.Name); rank != -1 { var ( // specific values used for sorting that need to be calculated based on all manifests from the repo - repoDownloads = 0 - repoLastUpdated time.Time - firstImageChecked = true - osSet = map[string]bool{} - archSet = map[string]bool{} - isSigned = false + repoDownloads = 0 + repoLastUpdated = time.Time{} + noImageChecked = true + osSet = map[string]bool{} + archSet = map[string]bool{} + isSigned = false ) for _, descriptor := range repoMeta.Tags { @@ -844,17 +844,11 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter archSet[arch] = true } - if firstImageChecked || repoLastUpdated.Before(manifestFilterData.LastUpdated) { - repoLastUpdated = manifestFilterData.LastUpdated - firstImageChecked = false - - isSigned = manifestFilterData.IsSigned - } + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, + noImageChecked, manifestFilterData) manifestMetadataMap[descriptor.Digest] = manifestMeta case ispec.MediaTypeImageIndex: - var indexLastUpdated time.Time - indexDigest := descriptor.Digest indexData, err := dwr.fetchIndexDataWithCheck(indexDigest, indexDataMap) //nolint:contextcheck @@ -865,7 +859,7 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter } // this also updates manifestMetadataMap - imageFilterData, err := dwr.collectImageIndexFilterInfo(indexDigest, repoMeta, indexData, //nolint:contextcheck + indexFilterData, err := dwr.collectImageIndexFilterInfo(indexDigest, repoMeta, indexData, //nolint:contextcheck manifestMetadataMap) if err != nil { return []repodb.RepoMetadata{}, map[string]repodb.ManifestMetadata{}, map[string]repodb.IndexData{}, @@ -873,21 +867,18 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter fmt.Errorf("%w", err) } - for _, arch := range imageFilterData.ArchList { + for _, arch := range indexFilterData.ArchList { archSet[arch] = true } - for _, os := range imageFilterData.OsList { + for _, os := range indexFilterData.OsList { osSet[os] = true } - repoDownloads += imageFilterData.DownloadCount + repoDownloads += indexFilterData.DownloadCount - if repoLastUpdated.Before(imageFilterData.LastUpdated) { - repoLastUpdated = indexLastUpdated - - isSigned = imageFilterData.IsSigned - } + repoLastUpdated, noImageChecked, isSigned = common.CheckImageLastUpdated(repoLastUpdated, isSigned, + noImageChecked, indexFilterData) indexDataMap[indexDigest] = indexData default: @@ -898,9 +889,11 @@ func (dwr *DBWrapper) SearchRepos(ctx context.Context, searchText string, filter } repoFilterData := repodb.FilterData{ - OsList: common.GetMapKeys(osSet), - ArchList: common.GetMapKeys(archSet), - IsSigned: isSigned, + OsList: common.GetMapKeys(osSet), + ArchList: common.GetMapKeys(archSet), + LastUpdated: repoLastUpdated, + DownloadCount: repoDownloads, + IsSigned: isSigned, } if !common.AcceptedByFilter(filter, repoFilterData) {