From c289be306771bd9a77d6d3199e9df99aec0c9a3f Mon Sep 17 00:00:00 2001 From: stonezdj Date: Mon, 18 Sep 2023 14:31:19 +0800 Subject: [PATCH] Refactor notification of delete project fixes #18250 Signed-off-by: stonezdj --- src/controller/event/handler/init.go | 1 + .../event/handler/internal/artifact.go | 19 ++++++++ .../event/handler/internal/artifact_test.go | 45 +++++++++++++++++++ src/controller/immutable/controller.go | 14 ++++++ src/controller/retention/controller.go | 17 +++++++ src/pkg/retention/dao/retention.go | 14 ++++++ src/pkg/retention/manager.go | 16 +++++++ 7 files changed, 126 insertions(+) diff --git a/src/controller/event/handler/init.go b/src/controller/event/handler/init.go index 2510b08e4c12..f12ef938d63a 100644 --- a/src/controller/event/handler/init.go +++ b/src/controller/event/handler/init.go @@ -70,6 +70,7 @@ func init() { _ = notifier.Subscribe(event.TopicPullArtifact, &internal.Handler{}) _ = notifier.Subscribe(event.TopicPushArtifact, &internal.Handler{}) _ = notifier.Subscribe(event.TopicDeleteArtifact, &internal.Handler{}) + _ = notifier.Subscribe(event.TopicDeleteProject, &internal.Handler{}) _ = task.RegisterTaskStatusChangePostFunc(job.ReplicationVendorType, func(ctx context.Context, taskID int64, status string) error { notification.AddEvent(ctx, &metadata.ReplicationMetaData{ diff --git a/src/controller/event/handler/internal/artifact.go b/src/controller/event/handler/internal/artifact.go index fc89eb6e02d7..f989485d8342 100644 --- a/src/controller/event/handler/internal/artifact.go +++ b/src/controller/event/handler/internal/artifact.go @@ -26,7 +26,9 @@ import ( "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/event/operator" + "github.com/goharbor/harbor/src/controller/immutable" "github.com/goharbor/harbor/src/controller/repository" + "github.com/goharbor/harbor/src/controller/retention" "github.com/goharbor/harbor/src/controller/tag" "github.com/goharbor/harbor/src/jobservice/job" "github.com/goharbor/harbor/src/lib/config" @@ -102,6 +104,8 @@ func (a *Handler) Handle(ctx context.Context, value interface{}) error { return a.onPush(ctx, v.ArtifactEvent) case *event.DeleteArtifactEvent: return a.onDelete(ctx, v.ArtifactEvent) + case *event.DeleteProjectEvent: + return a.onProjectDelete(ctx, v) default: log.Errorf("Can not handler this event type! %#v", v) } @@ -317,6 +321,21 @@ func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) erro return nil } +func (a *Handler) onProjectDelete(ctx context.Context, event *event.DeleteProjectEvent) error { + log.Infof("delete project id: %d", event.ProjectID) + // delete tag immutable + err := immutable.Ctr.DeleteImmutableRuleByProject(ctx, event.ProjectID) + if err != nil { + log.Errorf("failed to delete immutable rule, error %v", err) + } + // delete tag retention + err = retention.Ctl.DeleteRetentionByProject(ctx, event.ProjectID) + if err != nil { + log.Errorf("failed to delete retention rule, error %v", 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$+--` // verify it by the prefix `robot$+` diff --git a/src/controller/event/handler/internal/artifact_test.go b/src/controller/event/handler/internal/artifact_test.go index 23584a55f1d0..631be9b30396 100644 --- a/src/controller/event/handler/internal/artifact_test.go +++ b/src/controller/event/handler/internal/artifact_test.go @@ -24,13 +24,16 @@ import ( common_dao "github.com/goharbor/harbor/src/common/dao" "github.com/goharbor/harbor/src/controller/event" + "github.com/goharbor/harbor/src/controller/immutable" "github.com/goharbor/harbor/src/controller/scanner" "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/artifact" _ "github.com/goharbor/harbor/src/pkg/config/db" + immutableModel "github.com/goharbor/harbor/src/pkg/immutable/model" "github.com/goharbor/harbor/src/pkg/project" + "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/pkg/repository/model" "github.com/goharbor/harbor/src/pkg/tag" tagmodel "github.com/goharbor/harbor/src/pkg/tag/model/tag" @@ -162,6 +165,48 @@ func (suite *ArtifactHandlerTestSuite) TestOnPull() { }, 3*asyncFlushDuration, asyncFlushDuration/2, "wait for pull_count async update") } +func (suite *ArtifactHandlerTestSuite) TestOnProjectDelete() { + // create project + projID, err := project.New().Create(suite.ctx, &models.Project{Name: "test-project", OwnerID: 1}) + suite.Nil(err) + + defer project.New().Delete(suite.ctx, projID) + immutableRule := &immutableModel.Metadata{ + ProjectID: projID, + Priority: 1, + Action: "immutable", + Template: "immutable_template", + TagSelectors: []*immutableModel.Selector{ + { + Kind: "doublestar", + Decoration: "matches", + Pattern: "release-**", + }, + }, + ScopeSelectors: map[string][]*immutableModel.Selector{ + "repository": { + { + Kind: "doublestar", + Decoration: "repoMatches", + Pattern: "redis", + }, + }, + }, + } + // create immutable rule + immutableID, err := immutable.Ctr.CreateImmutableRule(suite.ctx, immutableRule) + suite.Nil(err) + + // emit delete project event + event := &event.DeleteProjectEvent{ProjectID: projID} + err = suite.handler.onProjectDelete(suite.ctx, event) + suite.Nil(err) + + // check if immutable rule is deleted + _, err = immutable.Ctr.GetImmutableRule(suite.ctx, immutableID) + suite.NotNil(err) +} + func (suite *ArtifactHandlerTestSuite) TestOnDelete() { evt := &event.ArtifactEvent{Artifact: &artifact.Artifact{ID: 1, RepositoryID: 1, Digest: "mock-digest", References: []*artifact.Reference{{ChildDigest: "ref-1", ChildID: 2}, {ChildDigest: "ref-2", ChildID: 3}}}} suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(1)).Return(nil).Times(1) diff --git a/src/controller/immutable/controller.go b/src/controller/immutable/controller.go index 186fea48070c..4fc46ec5aec1 100644 --- a/src/controller/immutable/controller.go +++ b/src/controller/immutable/controller.go @@ -47,6 +47,9 @@ type Controller interface { // Count count the immutable rules Count(ctx context.Context, query *q.Query) (int64, error) + + // DeleteImmutableRuleByProject delete immuatable rules with project id + DeleteImmutableRuleByProject(ctx context.Context, projectID int64) error } // DefaultAPIController ... @@ -54,6 +57,17 @@ type DefaultAPIController struct { manager immutable.Manager } +func (r *DefaultAPIController) DeleteImmutableRuleByProject(ctx context.Context, projectID int64) error { + rules, err := r.ListImmutableRules(ctx, q.New(q.KeyWords{"ProjectID": projectID})) + if err != nil { + return err + } + for _, rule := range rules { + r.DeleteImmutableRule(ctx, rule.ID) + } + return nil +} + // GetImmutableRule ... func (r *DefaultAPIController) GetImmutableRule(ctx context.Context, id int64) (*model.Metadata, error) { return r.manager.GetImmutableRule(ctx, id) diff --git a/src/controller/retention/controller.go b/src/controller/retention/controller.go index ef79c5b6a6b0..986268e58cbe 100644 --- a/src/controller/retention/controller.go +++ b/src/controller/retention/controller.go @@ -62,6 +62,8 @@ type Controller interface { GetRetentionExecTaskLog(ctx context.Context, taskID int64) ([]byte, error) GetRetentionExecTask(ctx context.Context, taskID int64) (*retention.Task, error) + // DeleteRetentionByProject delete retetion rule by project id + DeleteRetentionByProject(ctx context.Context, projectID int64) error } var ( @@ -405,6 +407,21 @@ func (r *defaultController) UpdateTaskInfo(ctx context.Context, taskID int64, to return r.taskMgr.UpdateExtraAttrs(ctx, taskID, t.ExtraAttrs) } +func (r *defaultController) DeleteRetentionByProject(ctx context.Context, projectID int64) error { + policyIDs, err := r.manager.ListPolicyIDs(ctx, + q.New(q.KeyWords{"scope_level": "project", + "scope_reference": fmt.Sprintf("%d", projectID)})) + if err != nil { + return err + } + for _, policyID := range policyIDs { + if err := r.DeleteRetention(ctx, policyID); err != nil { + return err + } + } + return nil +} + // NewController ... func NewController() Controller { retentionMgr := retention.NewManager() diff --git a/src/pkg/retention/dao/retention.go b/src/pkg/retention/dao/retention.go index fca8fd992ece..7106aa17f6b8 100644 --- a/src/pkg/retention/dao/retention.go +++ b/src/pkg/retention/dao/retention.go @@ -18,6 +18,7 @@ import ( "context" "github.com/goharbor/harbor/src/lib/orm" + "github.com/goharbor/harbor/src/lib/q" "github.com/goharbor/harbor/src/pkg/retention/dao/models" ) @@ -67,3 +68,16 @@ func GetPolicy(ctx context.Context, id int64) (*models.RetentionPolicy, error) { } return p, nil } + +// ListPolicy list retention policy by query +func ListPolicy(ctx context.Context, query *q.Query) ([]*models.RetentionPolicy, error) { + plcs := []*models.RetentionPolicy{} + qs, err := orm.QuerySetter(ctx, &models.RetentionPolicy{}, query) + if err != nil { + return nil, err + } + if _, err = qs.All(&plcs); err != nil { + return nil, err + } + return plcs, nil +} diff --git a/src/pkg/retention/manager.go b/src/pkg/retention/manager.go index a04ac8674bb8..82c7023ca549 100644 --- a/src/pkg/retention/manager.go +++ b/src/pkg/retention/manager.go @@ -24,6 +24,7 @@ import ( "github.com/go-openapi/strfmt" "github.com/goharbor/harbor/src/common/utils" + "github.com/goharbor/harbor/src/lib/q" "github.com/goharbor/harbor/src/pkg/retention/dao" "github.com/goharbor/harbor/src/pkg/retention/dao/models" "github.com/goharbor/harbor/src/pkg/retention/policy" @@ -41,6 +42,8 @@ type Manager interface { DeletePolicy(ctx context.Context, id int64) error // Get the specified policy GetPolicy(ctx context.Context, id int64) (*policy.Metadata, error) + // List the retention policy with query conditions + ListPolicyIDs(ctx context.Context, query *q.Query) ([]int64, error) } // DefaultManager ... @@ -103,6 +106,19 @@ func (d *DefaultManager) GetPolicy(ctx context.Context, id int64) (*policy.Metad return p, nil } +// ListPolicyIDs list policy id by query +func (d *DefaultManager) ListPolicyIDs(ctx context.Context, query *q.Query) ([]int64, error) { + policyIDs := make([]int64, 0) + plcs, err := dao.ListPolicy(ctx, query) + if err != nil { + return nil, err + } + for _, p := range plcs { + policyIDs = append(policyIDs, p.ID) + } + return policyIDs, nil +} + // NewManager ... func NewManager() Manager { return &DefaultManager{}