mirror of
https://github.com/goharbor/harbor
synced 2025-04-27 17:03:07 +00:00
fix: clean up scan executions and reports after deleting artifact (#18693)
Cleanup the associated resources(scan executions and scan reports) after deletion of artifact. Fixes: #18634 Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
parent
e19ec9623b
commit
a98711c0fc
@ -70,6 +70,7 @@ func init() {
|
||||
// internal
|
||||
_ = notifier.Subscribe(event.TopicPullArtifact, &internal.Handler{})
|
||||
_ = notifier.Subscribe(event.TopicPushArtifact, &internal.Handler{})
|
||||
_ = notifier.Subscribe(event.TopicDeleteArtifact, &internal.Handler{})
|
||||
|
||||
_ = task.RegisterTaskStatusChangePostFunc(job.ReplicationVendorType, func(ctx context.Context, taskID int64, status string) error {
|
||||
notification.AddEvent(ctx, &metadata.ReplicationMetaData{
|
||||
|
@ -27,10 +27,13 @@ import (
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/repository"
|
||||
"github.com/goharbor/harbor/src/controller/tag"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/report"
|
||||
"github.com/goharbor/harbor/src/pkg/task"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -62,6 +65,11 @@ func init() {
|
||||
|
||||
// Handler preprocess artifact event data
|
||||
type Handler struct {
|
||||
// execMgr for managing executions
|
||||
execMgr task.ExecutionManager
|
||||
// reportMgr for managing scan reports
|
||||
reportMgr report.Manager
|
||||
|
||||
once sync.Once
|
||||
// pullCountStore caches the pull count group by repository
|
||||
// map[repositoryID]counts
|
||||
@ -87,6 +95,8 @@ func (a *Handler) Handle(ctx context.Context, value interface{}) error {
|
||||
return a.onPull(ctx, v.ArtifactEvent)
|
||||
case *event.PushArtifactEvent:
|
||||
return a.onPush(ctx, v.ArtifactEvent)
|
||||
case *event.DeleteArtifactEvent:
|
||||
return a.onDelete(ctx, v.ArtifactEvent)
|
||||
default:
|
||||
log.Errorf("Can not handler this event type! %#v", v)
|
||||
}
|
||||
@ -244,6 +254,35 @@ func (a *Handler) onPush(ctx context.Context, event *event.ArtifactEvent) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) error {
|
||||
execMgr := task.ExecMgr
|
||||
reportMgr := report.Mgr
|
||||
// for UT mock
|
||||
if a.execMgr != nil {
|
||||
execMgr = a.execMgr
|
||||
}
|
||||
if a.reportMgr != nil {
|
||||
reportMgr = a.reportMgr
|
||||
}
|
||||
|
||||
// clean up the scan executions of this artifact by id
|
||||
if err := execMgr.DeleteByVendor(ctx, job.ImageScanJobVendorType, event.Artifact.ID); err != nil {
|
||||
log.Errorf("failed to delete scan executions of artifact %d, error: %v", event.Artifact.ID, err)
|
||||
}
|
||||
// clean up the scan reports of this artifact and it's references by digest
|
||||
digests := []string{event.Artifact.Digest}
|
||||
if len(event.Artifact.References) > 0 {
|
||||
for _, ref := range event.Artifact.References {
|
||||
digests = append(digests, ref.ChildDigest)
|
||||
}
|
||||
}
|
||||
if err := reportMgr.DeleteByDigests(ctx, digests...); err != nil {
|
||||
log.Errorf("failed to delete scan reports of artifact %v, error: %v", digests, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isScannerUser check if the current user is a scanner user by its prefix
|
||||
// usually a scanner user should be named like `robot$<projectName>+<Scanner UUID (8byte)>-<Scanner Name>-<UUID>`
|
||||
// verify it by the prefix `robot$<projectName>+<Scanner UUID (8byte)>`
|
||||
|
@ -36,6 +36,8 @@ import (
|
||||
tagmodel "github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||
scannerCtlMock "github.com/goharbor/harbor/src/testing/controller/scanner"
|
||||
projectMock "github.com/goharbor/harbor/src/testing/pkg/project"
|
||||
reportMock "github.com/goharbor/harbor/src/testing/pkg/scan/report"
|
||||
taskMock "github.com/goharbor/harbor/src/testing/pkg/task"
|
||||
)
|
||||
|
||||
// ArtifactHandlerTestSuite is test suite for artifact handler.
|
||||
@ -46,6 +48,8 @@ type ArtifactHandlerTestSuite struct {
|
||||
handler *Handler
|
||||
projectManager project.Manager
|
||||
scannerCtl scanner.Controller
|
||||
reportMgr *reportMock.Manager
|
||||
execMgr *taskMock.ExecutionManager
|
||||
}
|
||||
|
||||
// TestArtifactHandler tests ArtifactHandler.
|
||||
@ -57,10 +61,12 @@ func TestArtifactHandler(t *testing.T) {
|
||||
func (suite *ArtifactHandlerTestSuite) SetupSuite() {
|
||||
common_dao.PrepareTestForPostgresSQL()
|
||||
config.Init()
|
||||
suite.handler = &Handler{}
|
||||
suite.ctx = orm.NewContext(context.TODO(), beegoorm.NewOrm())
|
||||
suite.projectManager = &projectMock.Manager{}
|
||||
suite.scannerCtl = &scannerCtlMock.Controller{}
|
||||
suite.execMgr = &taskMock.ExecutionManager{}
|
||||
suite.reportMgr = &reportMock.Manager{}
|
||||
suite.handler = &Handler{execMgr: suite.execMgr, reportMgr: suite.reportMgr}
|
||||
|
||||
// mock artifact
|
||||
_, err := pkg.ArtifactMgr.Create(suite.ctx, &artifact.Artifact{ID: 1, RepositoryID: 1})
|
||||
@ -152,6 +158,14 @@ func (suite *ArtifactHandlerTestSuite) TestOnPull() {
|
||||
}, 3*asyncFlushDuration, asyncFlushDuration/2, "wait for pull_count async update")
|
||||
}
|
||||
|
||||
func (suite *ArtifactHandlerTestSuite) TestOnDelete() {
|
||||
evt := &event.ArtifactEvent{Artifact: &artifact.Artifact{ID: 1, RepositoryID: 1, Digest: "mock-digest", References: []*artifact.Reference{{ChildDigest: "ref-1"}, {ChildDigest: "ref-2"}}}}
|
||||
suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(1)).Return(nil).Times(1)
|
||||
suite.reportMgr.On("DeleteByDigests", suite.ctx, "mock-digest", "ref-1", "ref-2").Return(nil).Times(1)
|
||||
err := suite.handler.onDelete(suite.ctx, evt)
|
||||
suite.Nil(err, "onDelete should return nil")
|
||||
}
|
||||
|
||||
func (suite *ArtifactHandlerTestSuite) TestIsScannerUser() {
|
||||
type args struct {
|
||||
prefix string
|
||||
|
Loading…
x
Reference in New Issue
Block a user