diff --git a/core/cmd/cmd.go b/core/cmd/cmd.go index 824e20472..ad291255d 100644 --- a/core/cmd/cmd.go +++ b/core/cmd/cmd.go @@ -110,6 +110,7 @@ import ( "github.com/horizoncd/horizon/pkg/cd" clustermetrcis "github.com/horizoncd/horizon/pkg/cluster/metrics" "github.com/horizoncd/horizon/pkg/environment/service" + eventservice "github.com/horizoncd/horizon/pkg/event/service" "github.com/horizoncd/horizon/pkg/grafana" "github.com/horizoncd/horizon/pkg/jobs" "github.com/horizoncd/horizon/pkg/jobs/autofree" @@ -431,6 +432,7 @@ func Init(ctx context.Context, flags *Flags, coreConfig *config.Config) { } groupSvc := groupservice.NewService(manager) + eventSvc := eventservice.New(manager) applicationSvc := applicationservice.NewService(groupSvc, manager) clusterSvc := clusterservice.NewService(applicationSvc, manager) userSvc := userservice.NewService(manager) @@ -454,6 +456,7 @@ func Init(ctx context.Context, flags *Flags, coreConfig *config.Config) { ApplicationSvc: applicationSvc, ClusterSvc: clusterSvc, GroupSvc: groupSvc, + EventSvc: eventSvc, UserSvc: userSvc, TokenSvc: tokenSvc, RoleService: roleService, diff --git a/core/common/const.go b/core/common/const.go index 3ff1df7cd..0820add15 100644 --- a/core/common/const.go +++ b/core/common/const.go @@ -108,6 +108,8 @@ const ( ResourceWebhook = "webhooks" ResourceWebhookLog = "webhooklogs" + + ResourceMember = "members" ) const ( diff --git a/core/controller/application/controller.go b/core/controller/application/controller.go index c6f85d0f1..bda346b95 100644 --- a/core/controller/application/controller.go +++ b/core/controller/application/controller.go @@ -32,8 +32,8 @@ import ( codemodels "github.com/horizoncd/horizon/pkg/cluster/code" clustermanager "github.com/horizoncd/horizon/pkg/cluster/manager" perror "github.com/horizoncd/horizon/pkg/errors" - eventmanager "github.com/horizoncd/horizon/pkg/event/manager" eventmodels "github.com/horizoncd/horizon/pkg/event/models" + eventservice "github.com/horizoncd/horizon/pkg/event/service" groupmanager "github.com/horizoncd/horizon/pkg/group/manager" groupsvc "github.com/horizoncd/horizon/pkg/group/service" "github.com/horizoncd/horizon/pkg/member" @@ -49,7 +49,6 @@ import ( usersvc "github.com/horizoncd/horizon/pkg/user/service" "github.com/horizoncd/horizon/pkg/util/errors" "github.com/horizoncd/horizon/pkg/util/jsonschema" - "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/permission" "github.com/horizoncd/horizon/pkg/util/validate" "github.com/horizoncd/horizon/pkg/util/wlog" @@ -95,7 +94,7 @@ type controller struct { clusterMgr clustermanager.Manager userSvc usersvc.Service memberManager member.Manager - eventMgr eventmanager.Manager + eventSvc eventservice.Service tagMgr tagmanager.Manager applicationRegionMgr applicationregionmanager.Manager pipelinemanager pipelinemanager.Manager @@ -116,7 +115,7 @@ func NewController(param *param.Param) Controller { clusterMgr: param.ClusterMgr, userSvc: param.UserSvc, memberManager: param.MemberMgr, - eventMgr: param.EventMgr, + eventSvc: param.EventSvc, tagMgr: param.TagMgr, applicationRegionMgr: param.ApplicationRegionMgr, pipelinemanager: param.PipelineMgr, @@ -309,16 +308,9 @@ func (c *controller) CreateApplication(ctx context.Context, groupID uint, request.TemplateInput.Pipeline, request.TemplateInput.Application) // 7. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceApplication, - EventType: eventmodels.ApplicationCreated, - ResourceID: ret.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } - + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceApplication, ret.ID, + eventmodels.ApplicationCreated, nil) + c.eventSvc.RecordMemberCreatedEvent(ctx, common.ResourceApplication, ret.ID) return ret, nil } @@ -436,16 +428,9 @@ func (c *controller) CreateApplicationV2(ctx context.Context, groupID uint, ret.Priority = *request.Priority } - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceApplication, - EventType: eventmodels.ApplicationCreated, - ResourceID: applicationDBModel.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } - + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceApplication, ret.ID, + eventmodels.ApplicationCreated, nil) + c.eventSvc.RecordMemberCreatedEvent(ctx, common.ResourceApplication, ret.ID) return ret, nil } @@ -498,15 +483,8 @@ func (c *controller) UpdateApplication(ctx context.Context, id uint, } // 5. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceApplication, - EventType: eventmodels.ApplicationUpdated, - ResourceID: applicationModel.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceApplication, applicationModel.ID, + eventmodels.ApplicationUpdated, nil) // 6. get fullPath group, err := c.groupSvc.GetChildByID(ctx, appExistsInDB.GroupID) @@ -591,15 +569,8 @@ func (c *controller) UpdateApplicationV2(ctx context.Context, id uint, } // 6. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceApplication, - EventType: eventmodels.ApplicationUpdated, - ResourceID: appExistsInDB.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceApplication, appExistsInDB.ID, + eventmodels.ApplicationUpdated, nil) return err } @@ -652,16 +623,8 @@ func (c *controller) DeleteApplication(ctx context.Context, id uint, hard bool) } // 4. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceApplication, - EventType: eventmodels.ApplicationDeleted, - ResourceID: id, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } - + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceApplication, id, + eventmodels.ApplicationDeleted, nil) return nil } diff --git a/core/controller/application/controller_test.go b/core/controller/application/controller_test.go index f18b2d59a..eff244684 100644 --- a/core/controller/application/controller_test.go +++ b/core/controller/application/controller_test.go @@ -32,6 +32,7 @@ import ( codemodels "github.com/horizoncd/horizon/pkg/cluster/code" clustermodels "github.com/horizoncd/horizon/pkg/cluster/models" eventmodels "github.com/horizoncd/horizon/pkg/event/models" + eventservice "github.com/horizoncd/horizon/pkg/event/service" groupmodels "github.com/horizoncd/horizon/pkg/group/models" groupservice "github.com/horizoncd/horizon/pkg/group/service" membermodels "github.com/horizoncd/horizon/pkg/member/models" @@ -41,6 +42,7 @@ import ( tmodels "github.com/horizoncd/horizon/pkg/template/models" trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" trschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" + usermodel "github.com/horizoncd/horizon/pkg/user/models" userservice "github.com/horizoncd/horizon/pkg/user/service" "github.com/golang/mock/gomock" @@ -293,6 +295,9 @@ func TestMain(m *testing.M) { if err := db.AutoMigrate(&eventmodels.Event{}); err != nil { panic(err) } + if err := db.AutoMigrate(&usermodel.User{}); err != nil { + panic(err) + } ctx = context.TODO() ctx = context.WithValue(ctx, common.UserContextKey(), &userauth.DefaultInfo{ Name: "Tony", @@ -362,7 +367,8 @@ func Test(t *testing.T) { templateReleaseMgr: manager.TemplateReleaseMgr, clusterMgr: manager.ClusterMgr, userSvc: userservice.NewService(manager), - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), + memberManager: manager.MemberMgr, } group, err := manager.GroupMgr.Create(ctx, &groupmodels.Group{ @@ -517,7 +523,8 @@ func TestV2(t *testing.T) { templateReleaseMgr: manager.TemplateReleaseMgr, clusterMgr: manager.ClusterMgr, userSvc: userservice.NewService(manager), - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), + memberManager: manager.MemberMgr, } group, err := manager.GroupMgr.Create(ctx, &groupmodels.Group{ diff --git a/core/controller/cluster/controller.go b/core/controller/cluster/controller.go index 046bf0238..6de7c35c9 100644 --- a/core/controller/cluster/controller.go +++ b/core/controller/cluster/controller.go @@ -39,7 +39,7 @@ import ( envmanager "github.com/horizoncd/horizon/pkg/environment/manager" "github.com/horizoncd/horizon/pkg/environment/service" environmentregionmapper "github.com/horizoncd/horizon/pkg/environmentregion/manager" - eventmanager "github.com/horizoncd/horizon/pkg/event/manager" + eventservice "github.com/horizoncd/horizon/pkg/event/service" grafanaservice "github.com/horizoncd/horizon/pkg/grafana" groupmanager "github.com/horizoncd/horizon/pkg/group/manager" groupsvc "github.com/horizoncd/horizon/pkg/group/service" @@ -159,7 +159,7 @@ type controller struct { grafanaService grafanaservice.Service grafanaConfig grafana.Config buildSchema *build.Schema - eventMgr eventmanager.Manager + eventSvc eventservice.Service tokenSvc tokenservice.Service tokenConfig token.Config templateUpgradeMapper template.UpgradeMapper @@ -201,7 +201,7 @@ func NewController(config *config.Config, param *param.Param) Controller { grafanaService: param.GrafanaService, grafanaConfig: config.GrafanaConfig, buildSchema: param.BuildSchema, - eventMgr: param.EventMgr, + eventSvc: param.EventSvc, tokenSvc: param.TokenSvc, tokenConfig: config.TokenConfig, templateUpgradeMapper: config.TemplateUpgradeMapper, diff --git a/core/controller/cluster/controller_basic.go b/core/controller/cluster/controller_basic.go index b71d86798..b8fee2f12 100644 --- a/core/controller/cluster/controller_basic.go +++ b/core/controller/cluster/controller_basic.go @@ -553,16 +553,9 @@ func (c *controller) CreateCluster(ctx context.Context, applicationID uint, envi r.TemplateInput.Pipeline, r.TemplateInput.Application) // 11. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterCreated, - ResourceID: ret.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } - + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, ret.ID, + eventmodels.ClusterCreated, nil) + c.eventSvc.RecordMemberCreatedEvent(ctx, common.ResourceCluster, ret.ID) return ret, nil } @@ -725,15 +718,8 @@ func (c *controller) UpdateCluster(ctx context.Context, clusterID uint, } // 6. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterUpdated, - ResourceID: cluster.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventmodels.ClusterUpdated, nil) // 7. get full path group, err := c.groupSvc.GetChildByID(ctx, application.GroupID) @@ -917,16 +903,8 @@ func (c *controller) DeleteCluster(ctx context.Context, clusterID uint, hard boo } // 5. record event - if _, err := c.eventMgr.CreateEvent(newctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterDeleted, - ResourceID: clusterID, - }, - ReqID: rid, - }); err != nil { - log.Warningf(newctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(newctx, common.ResourceCluster, clusterID, + eventmodels.ClusterDeleted, nil) }() return nil @@ -997,15 +975,8 @@ func (c *controller) FreeCluster(ctx context.Context, clusterID uint) (err error } // 4. create event - if _, err := c.eventMgr.CreateEvent(newctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterFreed, - ResourceID: clusterID, - }, - }); err != nil { - log.Warningf(newctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(newctx, common.ResourceCluster, clusterID, + eventmodels.ClusterFreed, nil) }() return nil diff --git a/core/controller/cluster/controller_basic_test.go b/core/controller/cluster/controller_basic_test.go index 0aee90826..67b07a6a0 100644 --- a/core/controller/cluster/controller_basic_test.go +++ b/core/controller/cluster/controller_basic_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/golang/mock/gomock" + eventservice "github.com/horizoncd/horizon/pkg/event/service" "github.com/stretchr/testify/assert" "github.com/horizoncd/horizon/core/common" @@ -101,7 +102,7 @@ func testListClusterByNameFuzzily(t *testing.T) { applicationSvc: applicationservice.NewService(groupservice.NewService(manager), manager), groupManager: manager.GroupMgr, memberManager: manager.MemberMgr, - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), commitGetter: commitGetter, } @@ -218,7 +219,7 @@ func testListUserClustersByNameFuzzily(t *testing.T) { applicationSvc: applicationservice.NewService(groupservice.NewService(manager), manager), groupManager: manager.GroupMgr, memberManager: manager.MemberMgr, - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), commitGetter: commitGetter, } @@ -306,7 +307,7 @@ func testControllerFreeOrDeleteClusterFailed(t *testing.T) { groupManager: manager.GroupMgr, envMgr: manager.EnvMgr, regionMgr: manager.RegionMgr, - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), } id, err := registrydao.NewDAO(db).Create(ctx, ®istrymodels.Registry{ diff --git a/core/controller/cluster/controller_basic_v2.go b/core/controller/cluster/controller_basic_v2.go index 9486e33c8..2563845f1 100644 --- a/core/controller/cluster/controller_basic_v2.go +++ b/core/controller/cluster/controller_basic_v2.go @@ -33,7 +33,6 @@ import ( "github.com/horizoncd/horizon/pkg/templaterelease/models" templateschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" "github.com/horizoncd/horizon/pkg/util/jsonschema" - "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/mergemap" "github.com/horizoncd/horizon/pkg/util/validate" @@ -245,16 +244,9 @@ func (c *controller) CreateClusterV2(ctx context.Context, } // 12. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterCreated, - ResourceID: cluster.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } - + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, ret.ID, + eventmodels.ClusterCreated, nil) + c.eventSvc.RecordMemberCreatedEvent(ctx, common.ResourceCluster, ret.ID) // 13. customize response return ret, nil } @@ -519,15 +511,8 @@ func (c *controller) UpdateClusterV2(ctx context.Context, clusterID uint, } // 7. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterUpdated, - ResourceID: cluster.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventmodels.ClusterUpdated, nil) // 8. update cluster in db clusterModel, tags := r.toClusterModel(cluster, expireSeconds, environmentName, @@ -685,7 +670,8 @@ func (c *controller) CreatePipelineRun(ctx context.Context, clusterID uint, return nil, err } - c.recordPipelinerunCreatedEvent(ctx, pipelineRun) + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourcePipelinerun, pipelineRun.ID, + eventmodels.PipelinerunCreated, nil) firstCanRollbackPipelinerun, err := c.prMgr.PipelineRun.GetFirstCanRollbackPipelinerun(ctx, pipelineRun.ClusterID) if err != nil { @@ -830,16 +816,3 @@ func (c *controller) createPipelineRun(ctx context.Context, clusterID uint, ConfigCommit: configCommitSHA, }, nil } - -func (c *controller) recordPipelinerunCreatedEvent(ctx context.Context, pr *prmodels.Pipelinerun) { - _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceID: pr.ID, - ResourceType: common.ResourcePipelinerun, - EventType: eventmodels.PipelinerunCreated, - }, - }) - if err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } -} diff --git a/core/controller/cluster/controller_basic_v2_test.go b/core/controller/cluster/controller_basic_v2_test.go index 1bff143c7..8d8db47e5 100644 --- a/core/controller/cluster/controller_basic_v2_test.go +++ b/core/controller/cluster/controller_basic_v2_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/golang/mock/gomock" + eventservice "github.com/horizoncd/horizon/pkg/event/service" "github.com/stretchr/testify/assert" "github.com/horizoncd/horizon/core/common" @@ -62,7 +63,7 @@ func TestCreatePipelineRun(t *testing.T) { regionMgr: param.RegionMgr, clusterGitRepo: mockClusterGitRepo, commitGetter: mockGitGetter, - eventMgr: param.EventMgr, + eventSvc: eventservice.New(param), } _, err := param.UserMgr.Create(ctx, &usermodel.User{ diff --git a/core/controller/cluster/controller_internal.go b/core/controller/cluster/controller_internal.go index 49bd1e956..2b4f98cb5 100644 --- a/core/controller/cluster/controller_internal.go +++ b/core/controller/cluster/controller_internal.go @@ -152,15 +152,8 @@ func (c *controller) InternalDeploy(ctx context.Context, clusterID uint, } // 10. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterBuildDeployed, - ResourceID: cluster.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventmodels.ClusterBuildDeployed, nil) return &InternalDeployResponse{ PipelinerunID: pr.ID, diff --git a/core/controller/cluster/controller_internal_v2.go b/core/controller/cluster/controller_internal_v2.go index cc18ee353..e57c4c9ed 100644 --- a/core/controller/cluster/controller_internal_v2.go +++ b/core/controller/cluster/controller_internal_v2.go @@ -24,7 +24,6 @@ import ( userauth "github.com/horizoncd/horizon/pkg/authentication/user" "github.com/horizoncd/horizon/pkg/cd" "github.com/horizoncd/horizon/pkg/cluster/gitrepo" - "github.com/horizoncd/horizon/pkg/cluster/models" perror "github.com/horizoncd/horizon/pkg/errors" eventmodels "github.com/horizoncd/horizon/pkg/event/models" prmodels "github.com/horizoncd/horizon/pkg/pr/models" @@ -179,7 +178,12 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, } // 10. record cluster event - c.recordClusterEvent(ctx, pr, cluster) + eventType := eventmodels.ClusterDeployed + if pr.Action == prmodels.ActionBuildDeploy { + eventType = eventmodels.ClusterBuildDeployed + } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventType, nil) return &InternalDeployResponseV2{ PipelinerunID: pr.ID, @@ -187,24 +191,6 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, }, nil } -func (c *controller) recordClusterEvent(ctx context.Context, pr *prmodels.Pipelinerun, cluster *models.Cluster) { - _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: func() string { - if pr.Action == prmodels.ActionBuildDeploy { - return eventmodels.ClusterBuildDeployed - } - return eventmodels.ClusterDeployed - }(), - ResourceID: cluster.ID, - }, - }) - if err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } -} - func (c *controller) retrieveClaimsAndUser(ctx context.Context) (*tokenservice.Claims, *usermodel.User, error) { jwtTokenString, err := common.JWTTokenStringFromContext(ctx) if err != nil { diff --git a/core/controller/cluster/controller_operation.go b/core/controller/cluster/controller_operation.go index 4e747fd3b..c817d2b8e 100644 --- a/core/controller/cluster/controller_operation.go +++ b/core/controller/cluster/controller_operation.go @@ -103,15 +103,8 @@ func (c *controller) Restart(ctx context.Context, clusterID uint) (_ *Pipelineru } // 5. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterRestarted, - ResourceID: cluster.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventmodels.ClusterRestarted, nil) return &PipelinerunIDResponse{ PipelinerunID: prCreated.ID, @@ -424,15 +417,8 @@ func (c *controller) Rollback(ctx context.Context, } // 10. record event - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterRollbacked, - ResourceID: cluster.ID, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventmodels.ClusterRollbacked, nil) return &PipelinerunIDResponse{ PipelinerunID: prCreated.ID, @@ -608,16 +594,8 @@ func (c *controller) DeleteClusterPods(ctx context.Context, clusterID uint, podN log.Warningf(ctx, "failed to marshal podNames: %v", err.Error()) } podNameEncoded := string(podNameEncodedBts) - if _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ - EventSummary: eventmodels.EventSummary{ - ResourceType: common.ResourceCluster, - EventType: eventmodels.ClusterPodsRescheduled, - ResourceID: cluster.ID, - Extra: &podNameEncoded, - }, - }); err != nil { - log.Warningf(ctx, "failed to create event, err: %s", err.Error()) - } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceCluster, cluster.ID, + eventmodels.ClusterPodsRescheduled, &podNameEncoded) return ofBatchResp(result), nil } diff --git a/core/controller/cluster/controller_test.go b/core/controller/cluster/controller_test.go index 29183df60..6f9cf69b3 100644 --- a/core/controller/cluster/controller_test.go +++ b/core/controller/cluster/controller_test.go @@ -26,6 +26,7 @@ import ( tektoncollectormock "github.com/horizoncd/horizon/mock/pkg/cluster/tekton/collector" clustercd "github.com/horizoncd/horizon/pkg/cd" + eventservice "github.com/horizoncd/horizon/pkg/event/service" templatemodels "github.com/horizoncd/horizon/pkg/template/models" v1 "k8s.io/api/core/v1" @@ -653,7 +654,8 @@ func test(t *testing.T) { schemaTagManager: manager.ClusterSchemaTagMgr, tagMgr: tagManager, applicationGitRepo: applicationGitRepo, - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), + memberManager: manager.MemberMgr, tokenSvc: tokenservice.NewService(manager, tokenconfig.Config{ JwtSigningKey: "horizon", CallbackTokenExpireIn: time.Hour * 2, @@ -1420,7 +1422,8 @@ func testV2(t *testing.T) { tagMgr: manager.TagMgr, registryFty: registryFty, cd: mockCd, - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), + memberManager: manager.MemberMgr, } applicationGitRepo.EXPECT().GetApplication(gomock.Any(), applicationName, gomock.Any()). Return(&appgitrepo.GetResponse{ @@ -1645,8 +1648,9 @@ func testUpgrade(t *testing.T) { tagMgr: manager.TagMgr, registryFty: registryFty, cd: mockCd, - eventMgr: manager.EventMgr, + eventSvc: eventservice.New(manager), templateUpgradeMapper: templateUpgradeMapper, + memberManager: manager.MemberMgr, } applicationGitRepo.EXPECT().GetApplication(ctx, gomock.Any(), gomock.Any()). diff --git a/core/controller/member/controller.go b/core/controller/member/controller.go index ce3c55715..2481939d2 100644 --- a/core/controller/member/controller.go +++ b/core/controller/member/controller.go @@ -18,6 +18,9 @@ import ( "context" "strconv" + "github.com/horizoncd/horizon/core/common" + eventmodels "github.com/horizoncd/horizon/pkg/event/models" + eventservice "github.com/horizoncd/horizon/pkg/event/service" memberservice "github.com/horizoncd/horizon/pkg/member/service" "github.com/horizoncd/horizon/pkg/param" ) @@ -40,12 +43,14 @@ func NewController(param *param.Param) Controller { return &controller{ memberService: param.MemberService, convertHelper: New(param), + eventSvc: param.EventSvc, } } type controller struct { memberService memberservice.Service convertHelper ConvertMemberHelp + eventSvc eventservice.Service } func (c *controller) CreateMember(ctx context.Context, postMember *PostMember) (*Member, error) { @@ -57,6 +62,8 @@ func (c *controller) CreateMember(ctx context.Context, postMember *PostMember) ( if err != nil { return nil, err } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceMember, member.ID, + eventmodels.MemberCreated, nil) return retMember, nil } @@ -69,11 +76,23 @@ func (c *controller) UpdateMember(ctx context.Context, id uint, role string) (*M if err != nil { return nil, err } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceMember, member.ID, + eventmodels.MemberUpdated, nil) return retMember, nil } func (c *controller) RemoveMember(ctx context.Context, id uint) error { - return c.memberService.RemoveMember(ctx, id) + member, err := c.memberService.GetMember(ctx, id) + if err != nil { + return err + } + err = c.memberService.RemoveMember(ctx, id) + if err != nil { + return err + } + c.eventSvc.CreateEventIgnoreError(ctx, common.ResourceMember, member.ID, + eventmodels.MemberDeleted, nil) + return nil } func (c *controller) ListMember(ctx context.Context, resourceType string, id uint) ([]Member, error) { diff --git a/core/controller/member/controller_test.go b/core/controller/member/controller_test.go index 4020744ac..a4aa68561 100644 --- a/core/controller/member/controller_test.go +++ b/core/controller/member/controller_test.go @@ -19,6 +19,8 @@ import ( "testing" "github.com/golang/mock/gomock" + eventmodels "github.com/horizoncd/horizon/pkg/event/models" + eventservice "github.com/horizoncd/horizon/pkg/event/service" "github.com/stretchr/testify/assert" "gorm.io/gorm" @@ -55,6 +57,7 @@ var ( groupSvc groupservice.Service applicationSvc applicationservice.Service clusterSvc clusterservice.Service + eventSvc eventservice.Service ) var ( @@ -85,13 +88,15 @@ func createContext(t *testing.T) { // create table err := db.AutoMigrate(&models.Group{}, &usermodel.User{}, &appmodels.Application{}, &membermodels.Member{}, - &tmodels.Template{}, &trmodels.TemplateRelease{}) + &tmodels.Template{}, &trmodels.TemplateRelease{}, &eventmodels.Event{}) assert.Nil(t, err) groupCtl = group.NewController(¶m.Param{Manager: manager}) groupSvc = groupservice.NewService(manager) + applicationSvc = applicationservice.NewService(groupSvc, manager) clusterSvc = clusterservice.NewService(applicationSvc, manager) + eventSvc = eventservice.New(manager) } func MemberSame(m1, m2 Member) bool { @@ -140,6 +145,7 @@ func TestCreateGroupWithOwner(t *testing.T) { GroupSvc: groupSvc, ApplicationSvc: applicationSvc, ClusterSvc: clusterSvc, + EventSvc: eventSvc, }) CreateUsers(t) @@ -201,6 +207,7 @@ func TestCreateGetUpdateRemoveList(t *testing.T) { GroupSvc: groupSvc, ApplicationSvc: applicationSvc, ClusterSvc: clusterSvc, + EventSvc: eventSvc, }) // create group @@ -270,6 +277,7 @@ func TestTemplateMember(t *testing.T) { GroupSvc: groupSvc, ApplicationSvc: applicationSvc, ClusterSvc: clusterSvc, + EventSvc: eventSvc, }) onlyOwner := false diff --git a/core/http/api/v2/member/apis.go b/core/http/api/v2/member/apis.go index fbf5507fe..89cd7bab6 100644 --- a/core/http/api/v2/member/apis.go +++ b/core/http/api/v2/member/apis.go @@ -21,7 +21,9 @@ import ( "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/core/controller/member" + herrors "github.com/horizoncd/horizon/core/errors" memberctx "github.com/horizoncd/horizon/pkg/context" + perror "github.com/horizoncd/horizon/pkg/errors" membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/rbac/role" "github.com/horizoncd/horizon/pkg/server/response" @@ -234,6 +236,10 @@ func (a *API) DeleteMember(c *gin.Context) { } err = a.memberCtrl.RemoveMember(c, uint(uintID)) if err != nil { + if _, ok := perror.Cause(err).(*herrors.HorizonErrNotFound); ok { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } response.AbortWithError(c, err) return } diff --git a/mock/pkg/member/manager/mock_manager.go b/mock/pkg/member/manager/mock_manager.go index 971d1ad06..124e70eea 100644 --- a/mock/pkg/member/manager/mock_manager.go +++ b/mock/pkg/member/manager/mock_manager.go @@ -108,6 +108,21 @@ func (mr *MockManagerMockRecorder) GetByID(ctx, memberID interface{}) *gomock.Ca return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockManager)(nil).GetByID), ctx, memberID) } +// GetByIDIncludeSoftDelete mocks base method. +func (m *MockManager) GetByIDIncludeSoftDelete(ctx context.Context, memberID uint) (*models.Member, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByIDIncludeSoftDelete", ctx, memberID) + ret0, _ := ret[0].(*models.Member) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByIDIncludeSoftDelete indicates an expected call of GetByIDIncludeSoftDelete. +func (mr *MockManagerMockRecorder) GetByIDIncludeSoftDelete(ctx, memberID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByIDIncludeSoftDelete", reflect.TypeOf((*MockManager)(nil).GetByIDIncludeSoftDelete), ctx, memberID) +} + // HardDeleteMemberByResourceTypeID mocks base method. func (m *MockManager) HardDeleteMemberByResourceTypeID(ctx context.Context, resourceType string, resourceID uint) error { m.ctrl.T.Helper() diff --git a/pkg/event/manager/manager.go b/pkg/event/manager/manager.go index 0ed2c3219..2a456d5ca 100644 --- a/pkg/event/manager/manager.go +++ b/pkg/event/manager/manager.go @@ -137,6 +137,9 @@ var supportedEvents = map[string]string{ models.ClusterAction: "Cluster has triggered an action", models.ClusterPodsRescheduled: "Pods has been deleted to reschedule", models.ClusterKubernetesEvent: "Kubernetes event associated with cluster has been triggered", + models.MemberCreated: "New member has been created", + models.MemberUpdated: "Member has been updated", + models.MemberDeleted: "Member has been deleted", models.PipelinerunCreated: "New pipelinerun has been created", } diff --git a/pkg/event/models/event.go b/pkg/event/models/event.go index 5d356d3ef..13e2389b3 100644 --- a/pkg/event/models/event.go +++ b/pkg/event/models/event.go @@ -38,6 +38,9 @@ const ( ClusterFreed string = "clusters_freed" ClusterKubernetesEvent string = "clusters_kubernetes_event" ClusterAction = "clusters_action" + MemberCreated string = "members_created" + MemberUpdated string = "members_updated" + MemberDeleted string = "members_deleted" PipelinerunCreated string = "pipelineruns_created" // TODO: add group events ) diff --git a/pkg/event/service/service.go b/pkg/event/service/service.go new file mode 100644 index 000000000..c6068fbe3 --- /dev/null +++ b/pkg/event/service/service.go @@ -0,0 +1,98 @@ +package service + +import ( + "context" + + "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/pkg/event/manager" + "github.com/horizoncd/horizon/pkg/event/models" + membermanager "github.com/horizoncd/horizon/pkg/member" + membermodels "github.com/horizoncd/horizon/pkg/member/models" + "github.com/horizoncd/horizon/pkg/param/managerparam" + "github.com/horizoncd/horizon/pkg/util/log" +) + +type Service interface { + // CreateEventIgnoreError creates an event and ignore the error + CreateEventIgnoreError(ctx context.Context, resourceType string, + resourceID uint, eventType string, extra *string) []*models.Event + // CreateEventsIgnoreError creates events and ignore the error + CreateEventsIgnoreError(ctx context.Context, events ...*models.Event) []*models.Event + // RecordMemberCreatedEvent records members_created event for the given resource that is created + RecordMemberCreatedEvent(ctx context.Context, resourceType string, resourceID uint) []*models.Event +} + +type service struct { + eventMgr manager.Manager + memberMgr membermanager.Manager +} + +func New(manager *managerparam.Manager) Service { + return &service{ + eventMgr: manager.EventMgr, + memberMgr: manager.MemberMgr, + } +} + +func (s *service) CreateEventIgnoreError(ctx context.Context, resourceType string, + resourceID uint, eventType string, extra *string) []*models.Event { + events, err := s.eventMgr.CreateEvent(ctx, &models.Event{ + EventSummary: models.EventSummary{ + ResourceType: resourceType, + ResourceID: resourceID, + EventType: eventType, + Extra: extra, + }, + }) + if err != nil { + log.Warningf(ctx, "failed to create event, err: %s", err.Error()) + return nil + } + return events +} + +func (s *service) CreateEventsIgnoreError(ctx context.Context, events ...*models.Event) []*models.Event { + events, err := s.eventMgr.CreateEvent(ctx, events...) + if err != nil { + log.Warningf(ctx, "failed to create event, err: %s", err.Error()) + return nil + } + return events +} + +func (s *service) RecordMemberCreatedEvent(ctx context.Context, resourceType string, + resourceID uint) []*models.Event { + var members []membermodels.Member + var err error + switch resourceType { + case common.ResourceApplication: + members, err = s.memberMgr.ListDirectMember(ctx, membermodels.TypeApplication, resourceID) + case common.ResourceCluster: + members, err = s.memberMgr.ListDirectMember(ctx, membermodels.TypeApplicationCluster, resourceID) + default: + log.Warningf(ctx, "unsupported resource type: %s", resourceType) + return nil + } + if err != nil { + log.Warningf(ctx, "failed to list members of resource, err: %s", err.Error()) + return nil + } + events := make([]*models.Event, 0, len(members)) + for _, m := range members { + events = append(events, &models.Event{ + EventSummary: models.EventSummary{ + ResourceType: common.ResourceMember, + ResourceID: m.ID, + EventType: models.MemberCreated, + }, + }) + } + if len(events) > 0 { + retEvents, err := s.eventMgr.CreateEvent(ctx, events...) + if err != nil { + log.Warningf(ctx, "failed to create event, err: %s", err.Error()) + } + return retEvents + } + return nil +} diff --git a/pkg/eventhandler/wlgenerator/wlgenerator.go b/pkg/eventhandler/wlgenerator/wlgenerator.go index e2d29dd11..9edead72a 100644 --- a/pkg/eventhandler/wlgenerator/wlgenerator.go +++ b/pkg/eventhandler/wlgenerator/wlgenerator.go @@ -20,6 +20,8 @@ import ( "fmt" "net/http" + membermanager "github.com/horizoncd/horizon/pkg/member" + membermodels "github.com/horizoncd/horizon/pkg/member/models" prmodels "github.com/horizoncd/horizon/pkg/pr/models" "gopkg.in/yaml.v3" @@ -56,6 +58,7 @@ type MessageContent struct { Application *ApplicationInfo `json:"application,omitempty"` Cluster *ClusterInfo `json:"cluster,omitempty"` Pipelinerun *PipelinerunInfo `json:"pipelinerun,omitempty"` + Member *MemberInfo `json:"member,omitempty"` EventType string `json:"eventType,omitempty"` User *usermodels.UserBasic `json:"user,omitempty"` Extra *string `json:"extra,omitempty"` @@ -91,6 +94,16 @@ type PipelinerunInfo struct { GitRefType string `json:"gitRefType,omitempty"` } +// MemberInfo contains basic info of member +type MemberInfo struct { + ResourceCommonInfo + ResourceID uint `json:"resourceID"` + ResourceType membermodels.ResourceType `json:"resourceType"` + Role string `json:"role"` + MemberNameID uint `json:"memberNameID"` + MemberName string `json:"memberName"` +} + // WebhookLogGenerator generates webhook logs by events type WebhookLogGenerator struct { webhookMgr webhookmanager.Manager @@ -99,6 +112,7 @@ type WebhookLogGenerator struct { applicationMgr applicationmanager.Manager clusterMgr clustermanager.Manager prMgr *prmanager.PRManager + memberMgr membermanager.Manager userMgr usermanager.Manager } @@ -110,6 +124,7 @@ func NewWebhookLogGenerator(manager *managerparam.Manager) *WebhookLogGenerator applicationMgr: manager.ApplicationMgr, clusterMgr: manager.ClusterMgr, prMgr: manager.PRMgr, + memberMgr: manager.MemberMgr, userMgr: manager.UserMgr, } } @@ -120,6 +135,8 @@ type messageDependency struct { application *applicationmodels.Application cluster *clustermodels.Cluster pipelinerun *prmodels.Pipelinerun + member *membermodels.Member + userBasic *usermodels.UserBasic } // listSystemResources lists root group(0) as system resource @@ -184,6 +201,32 @@ func (w *WebhookLogGenerator) listAssociatedResourcesOfPipelinerun(ctx context.C return pr, cluster, resources } +// listAssociatedResourcesOfMember gets member by id and list all the parent resources +func (w *WebhookLogGenerator) listAssociatedResourcesOfMember(ctx context.Context, + id uint) (*membermodels.Member, *usermodels.UserBasic, map[string][]uint) { + member, err := w.memberMgr.GetByIDIncludeSoftDelete(ctx, id) + if err != nil { + log.Warningf(ctx, "member %d is not exist", id) + return nil, nil, nil + } + user, err := w.userMgr.GetUserByID(ctx, member.MemberNameID) + if err != nil { + log.Warningf(ctx, "user %d of member %d is not exist", member.MemberNameID, id) + return nil, nil, nil + } + var resources map[string][]uint + switch member.ResourceType { + case membermodels.TypeApplication: + _, resources = w.listAssociatedResourcesOfApp(ctx, member.ResourceID) + case membermodels.TypeApplicationCluster: + _, _, resources = w.listAssociatedResourcesOfCluster(ctx, member.ResourceID) + default: + // TODO: support member event of groups and templates + log.Warningf(ctx, "member event of resource type %s is unsupported yet", member.ResourceType) + } + return member, usermodels.ToUser(user), resources +} + // listAssociatedResources list all the associated resources of event to find all the webhooks func (w *WebhookLogGenerator) listAssociatedResources(ctx context.Context, e *models.Event) (*messageDependency, map[string][]uint) { @@ -192,6 +235,8 @@ func (w *WebhookLogGenerator) listAssociatedResources(ctx context.Context, cluster *clustermodels.Cluster application *applicationmodels.Application pr *prmodels.Pipelinerun + member *membermodels.Member + userBasic *usermodels.UserBasic dep = &messageDependency{} ) @@ -208,6 +253,10 @@ func (w *WebhookLogGenerator) listAssociatedResources(ctx context.Context, dep.cluster = cluster dep.pipelinerun = pr log.Debugf(ctx, "dep: %+v", dep) + case common.ResourceMember: + member, userBasic, resources = w.listAssociatedResourcesOfMember(ctx, e.ResourceID) + dep.member = member + dep.userBasic = userBasic default: log.Infof(ctx, "resource type %s is unsupported", e.ResourceType) @@ -288,6 +337,20 @@ func (w *WebhookLogGenerator) makeRequestBody(ctx context.Context, dep *messageD } } + if dep.event.ResourceType == common.ResourceMember && + dep.member != nil && dep.userBasic != nil { + message.Member = &MemberInfo{ + ResourceCommonInfo: ResourceCommonInfo{ + ID: dep.member.ID, + }, + ResourceID: dep.member.ResourceID, + ResourceType: dep.member.ResourceType, + Role: dep.member.Role, + MemberNameID: dep.member.MemberNameID, + MemberName: dep.userBasic.Name, + } + } + reqBody, err := json.Marshal(message) if err != nil { log.Errorf(ctx, fmt.Sprintf("failed to marshal message, error: %+v", err)) @@ -344,6 +407,8 @@ func (w *WebhookLogGenerator) Process(ctx context.Context, events []*models.Even application: dependency.application, cluster: dependency.cluster, pipelinerun: dependency.pipelinerun, + member: dependency.member, + userBasic: dependency.userBasic, } conditionsToQuery[event.ID] = append(conditionsToQuery[event.ID], webhook.ID) } diff --git a/pkg/member/dao/dao.go b/pkg/member/dao/dao.go index 3478911ab..58f2d347d 100644 --- a/pkg/member/dao/dao.go +++ b/pkg/member/dao/dao.go @@ -34,6 +34,7 @@ type DAO interface { Get(ctx context.Context, resourceType models.ResourceType, resourceID uint, memberType models.MemberType, memberInfo uint) (*models.Member, error) GetByID(ctx context.Context, memberID uint) (*models.Member, error) + GetByIDIncludeSoftDelete(ctx context.Context, memberID uint) (*models.Member, error) Delete(ctx context.Context, memberID uint) error HardDelete(ctx context.Context, resourceType string, resourceID uint) error DeleteByMemberNameID(ctx context.Context, memberNameID uint) error @@ -81,6 +82,24 @@ func (d *dao) GetByID(ctx context.Context, memberID uint) (*models.Member, error var member models.Member result := d.db.WithContext(ctx).Raw(common.MemberQueryByID, memberID).Scan(&member) if result.Error != nil { + if result.Error == gorm.ErrRecordNotFound { + return nil, herrors.NewErrNotFound(herrors.MemberInfoInDB, result.Error.Error()) + } + return nil, result.Error + } + if result.RowsAffected == 0 { + return nil, nil + } + return &member, nil +} + +func (d *dao) GetByIDIncludeSoftDelete(ctx context.Context, memberID uint) (*models.Member, error) { + var member models.Member + result := d.db.WithContext(ctx).Unscoped().Where("id = ?", memberID).First(&member) + if result.Error != nil { + if result.Error == gorm.ErrRecordNotFound { + return nil, herrors.NewErrNotFound(herrors.MemberInfoInDB, result.Error.Error()) + } return nil, result.Error } if result.RowsAffected == 0 { diff --git a/pkg/member/manager.go b/pkg/member/manager.go index d31febf65..f8307a188 100644 --- a/pkg/member/manager.go +++ b/pkg/member/manager.go @@ -34,6 +34,9 @@ type Manager interface { // GetByID get the member by ID GetByID(ctx context.Context, memberID uint) (*models.Member, error) + // GetByIDIncludeSoftDelete gets the member by ID including soft delete + GetByIDIncludeSoftDelete(ctx context.Context, memberID uint) (*models.Member, error) + // UpdateByID update a member by memberID UpdateByID(ctx context.Context, id uint, role string) (*models.Member, error) @@ -85,6 +88,10 @@ func (m *manager) GetByID(ctx context.Context, memberID uint) (*models.Member, e return m.dao.GetByID(ctx, memberID) } +func (m *manager) GetByIDIncludeSoftDelete(ctx context.Context, memberID uint) (*models.Member, error) { + return m.dao.GetByIDIncludeSoftDelete(ctx, memberID) +} + func (m *manager) UpdateByID(ctx context.Context, memberID uint, role string) (*models.Member, error) { return m.dao.UpdateByID(ctx, memberID, role) } diff --git a/pkg/member/manager_test.go b/pkg/member/manager_test.go index cc3150054..353a3d1b3 100644 --- a/pkg/member/manager_test.go +++ b/pkg/member/manager_test.go @@ -99,6 +99,10 @@ func TestBasic(t *testing.T) { retMember4, err := mgr.Get(ctx, member1.ResourceType, member1.ResourceID, models.MemberUser, member1.MemberNameID) assert.Nil(t, err) assert.Nil(t, retMember4) + + retMember5, err := mgr.GetByIDIncludeSoftDelete(ctx, retMember3.ID) + assert.Nil(t, err) + assert.NotNil(t, retMember5) } func TestList(t *testing.T) { diff --git a/pkg/param/param.go b/pkg/param/param.go index 2e4e48ac6..0fcdc7404 100644 --- a/pkg/param/param.go +++ b/pkg/param/param.go @@ -23,6 +23,7 @@ import ( clusterservice "github.com/horizoncd/horizon/pkg/cluster/service" "github.com/horizoncd/horizon/pkg/cluster/tekton/factory" "github.com/horizoncd/horizon/pkg/environment/service" + eventservice "github.com/horizoncd/horizon/pkg/event/service" "github.com/horizoncd/horizon/pkg/grafana" groupsvc "github.com/horizoncd/horizon/pkg/group/service" "github.com/horizoncd/horizon/pkg/hook/hook" @@ -51,6 +52,7 @@ type Param struct { ApplicationSvc applicationservice.Service ClusterSvc clusterservice.Service GroupSvc groupsvc.Service + EventSvc eventservice.Service UserSvc userservice.Service TokenSvc tokenservice.Service RoleService role.Service