diff --git a/src/common/dao/artifact.go b/src/common/dao/artifact.go index ac2b067ee..97098ddcf 100644 --- a/src/common/dao/artifact.go +++ b/src/common/dao/artifact.go @@ -41,6 +41,12 @@ func UpdateArtifactDigest(af *models.Artifact) error { return err } +// UpdateArtifactPullTime updates the pull time of the artifact. +func UpdateArtifactPullTime(af *models.Artifact) error { + _, err := GetOrmer().Update(af, "pull_time") + return err +} + // DeleteArtifact ... func DeleteArtifact(id int64) error { _, err := GetOrmer().QueryTable(&models.Artifact{}).Filter("ID", id).Delete() diff --git a/src/common/dao/artifact_test.go b/src/common/dao/artifact_test.go index 1869f2982..c893535c3 100644 --- a/src/common/dao/artifact_test.go +++ b/src/common/dao/artifact_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "time" ) func TestAddArtifact(t *testing.T) { @@ -58,6 +59,28 @@ func TestUpdateArtifactDigest(t *testing.T) { assert.Equal(t, af.Digest, "update_4321abcd") } +func TestUpdateArtifactPullTime(t *testing.T) { + timeNow := time.Now() + af := &models.Artifact{ + PID: 1, + Repo: "TestUpdateArtifactPullTime", + Tag: "v1.0", + Digest: "4321abcd", + Kind: "image", + PullTime: timeNow, + } + + // add + _, err := AddArtifact(af) + require.Nil(t, err) + + time.Sleep(time.Second * 1) + + af.PullTime = time.Now() + require.Nil(t, UpdateArtifactPullTime(af)) + assert.NotEqual(t, timeNow, af.PullTime) +} + func TestDeleteArtifact(t *testing.T) { af := &models.Artifact{ PID: 1, diff --git a/src/common/utils/utils.go b/src/common/utils/utils.go index d93c3c033..24a12258d 100644 --- a/src/common/utils/utils.go +++ b/src/common/utils/utils.go @@ -262,3 +262,8 @@ func IsContainIllegalChar(s string, illegalChar []string) bool { } return false } + +// IsDigest A sha256 is a string with 64 characters. +func IsDigest(ref string) bool { + return strings.HasPrefix(ref, "sha256:") && len(ref) == 71 +} diff --git a/src/common/utils/utils_test.go b/src/common/utils/utils_test.go index 206124610..437f16152 100644 --- a/src/common/utils/utils_test.go +++ b/src/common/utils/utils_test.go @@ -409,3 +409,9 @@ func TestGetStrValueOfAnyType(t *testing.T) { }) } } + +func TestIsDigest(t *testing.T) { + assert := assert.New(t) + assert.False(IsDigest("latest")) + assert.True(IsDigest("sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a7")) +} diff --git a/src/core/middlewares/contenttrust/handler.go b/src/core/middlewares/contenttrust/handler.go index 82ded4e5b..bcc4de44a 100644 --- a/src/core/middlewares/contenttrust/handler.go +++ b/src/core/middlewares/contenttrust/handler.go @@ -15,12 +15,12 @@ package contenttrust import ( + "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/notary" "github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/middlewares/util" "net/http" - "strings" ) // NotaryEndpoint ... @@ -75,7 +75,7 @@ func matchNotaryDigest(img util.ImageInfo) (bool, error) { return false, err } for _, t := range targets { - if isDigest(img.Reference) { + if utils.IsDigest(img.Reference) { d, err := notary.DigestFromTarget(t) if err != nil { return false, err @@ -99,8 +99,3 @@ func matchNotaryDigest(img util.ImageInfo) (bool, error) { log.Debugf("image: %#v, not found in notary", img) return false, nil } - -// A sha256 is a string with 64 characters. -func isDigest(ref string) bool { - return strings.HasPrefix(ref, "sha256:") && len(ref) == 71 -} diff --git a/src/core/middlewares/contenttrust/handler_test.go b/src/core/middlewares/contenttrust/handler_test.go index 05f29ff0e..d7767cac1 100644 --- a/src/core/middlewares/contenttrust/handler_test.go +++ b/src/core/middlewares/contenttrust/handler_test.go @@ -61,9 +61,3 @@ func TestMatchNotaryDigest(t *testing.T) { assert.Nil(err, "Unexpected error: %v, image: %#v, take 2", err, img2) assert.False(res2) } - -func TestIsDigest(t *testing.T) { - assert := assert.New(t) - assert.False(isDigest("latest")) - assert.True(isDigest("sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a7")) -} diff --git a/src/core/service/notifications/registry/handler.go b/src/core/service/notifications/registry/handler.go index d3530f979..0afd5233c 100644 --- a/src/core/service/notifications/registry/handler.go +++ b/src/core/service/notifications/registry/handler.go @@ -154,6 +154,45 @@ func (n *NotificationHandler) Post() { log.Errorf("Error happens when increasing pull count: %v", repository) } }() + + // update the artifact pull time, and ignore the events without tag. + if tag != "" { + go func() { + artifactQuery := &models.ArtifactQuery{ + PID: pro.ProjectID, + Repo: repository, + } + + // handle pull by tag or digest + pullByDigest := utils.IsDigest(tag) + if pullByDigest { + artifactQuery.Digest = tag + } else { + artifactQuery.Tag = tag + } + + afs, err := dao.ListArtifacts(artifactQuery) + if err != nil { + log.Errorf("Error occurred when to get artifact %v", err) + return + } + if len(afs) > 0 { + log.Warningf("get multiple artifact records when to update pull time with query :%d-%s-%s, "+ + "all of them will be updated.", artifactQuery.PID, artifactQuery.Repo, artifactQuery.Tag) + } + + // ToDo: figure out how to do batch update in Pg as beego orm doesn't support update multiple like insert does. + for _, af := range afs { + log.Debugf("Update the artifact: %s pull time.", af.Repo) + af.PullTime = time.Now() + if err := dao.UpdateArtifactPullTime(af); err != nil { + log.Errorf("Error happens when updating the pull time of artifact: %d-%s, with err: %v", + artifactQuery.PID, artifactQuery.Repo, err) + } + } + }() + } + } } }