This change adds a new websocket endpoint for database events. The events
endpoint allows clients to stream events as they happen in GARM. Events
are defined as a structure containning the event type (create, update, delete),
the database entity involved (instances, pools, repos, etc) and the payload
consisting of the object involved in the event. The payload translates
to the types normally returned by the API and can be deserialized as one
of the types present in the params package.
The events endpoint is a websocket endpoint and it accepts filters as
a simple json send over the websocket connection. The filters allows the
user to specify which entities are of interest, and which operations should
be returned. For example, you may be interested in changes made to pools
or runners, in which case you could create a filter that only returns
update operations for pools. Or update and delete operations.
The filters can be defined as:
{
"filters": [
{
"entity_type": "instance",
"operations": ["update", "delete"]
},
{
"entity_type": "pool"
},
],
"send_everything": false
}
This would return only update and delete events for instances and all events
for pools. Alternatively you can ask GARM to send you everything:
{
"send_everything": true
}
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
212 lines
6.1 KiB
Go
212 lines
6.1 KiB
Go
package watcher
|
|
|
|
import (
|
|
dbCommon "github.com/cloudbase/garm/database/common"
|
|
"github.com/cloudbase/garm/params"
|
|
)
|
|
|
|
type idGetter interface {
|
|
GetID() string
|
|
}
|
|
|
|
// WithAny returns a filter function that returns true if any of the provided filters return true.
|
|
// This filter is useful if for example you want to watch for update operations on any of the supplied
|
|
// entities.
|
|
// Example:
|
|
//
|
|
// // Watch for any update operation on repositories or organizations
|
|
// consumer.SetFilters(
|
|
// watcher.WithOperationTypeFilter(common.UpdateOperation),
|
|
// watcher.WithAny(
|
|
// watcher.WithEntityTypeFilter(common.RepositoryEntityType),
|
|
// watcher.WithEntityTypeFilter(common.OrganizationEntityType),
|
|
// ))
|
|
func WithAny(filters ...dbCommon.PayloadFilterFunc) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
for _, filter := range filters {
|
|
if filter(payload) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
// WithAll returns a filter function that returns true if all of the provided filters return true.
|
|
func WithAll(filters ...dbCommon.PayloadFilterFunc) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
for _, filter := range filters {
|
|
if !filter(payload) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
// WithEntityTypeFilter returns a filter function that filters payloads by entity type.
|
|
// The filter function returns true if the payload's entity type matches the provided entity type.
|
|
func WithEntityTypeFilter(entityType dbCommon.DatabaseEntityType) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
return payload.EntityType == entityType
|
|
}
|
|
}
|
|
|
|
// WithOperationTypeFilter returns a filter function that filters payloads by operation type.
|
|
func WithOperationTypeFilter(operationType dbCommon.OperationType) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
return payload.Operation == operationType
|
|
}
|
|
}
|
|
|
|
// WithEntityPoolFilter returns true if the change payload is a pool that belongs to the
|
|
// supplied Github entity. This is useful when an entity worker wants to watch for changes
|
|
// in pools that belong to it.
|
|
func WithEntityPoolFilter(ghEntity params.GithubEntity) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
switch payload.EntityType {
|
|
case dbCommon.PoolEntityType:
|
|
pool, ok := payload.Payload.(params.Pool)
|
|
if !ok {
|
|
return false
|
|
}
|
|
switch ghEntity.EntityType {
|
|
case params.GithubEntityTypeRepository:
|
|
if pool.RepoID != ghEntity.ID {
|
|
return false
|
|
}
|
|
case params.GithubEntityTypeOrganization:
|
|
if pool.OrgID != ghEntity.ID {
|
|
return false
|
|
}
|
|
case params.GithubEntityTypeEnterprise:
|
|
if pool.EnterpriseID != ghEntity.ID {
|
|
return false
|
|
}
|
|
default:
|
|
return false
|
|
}
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithEntityFilter returns a filter function that filters payloads by entity.
|
|
// Change payloads that match the entity type and ID will return true.
|
|
func WithEntityFilter(entity params.GithubEntity) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
if params.GithubEntityType(payload.EntityType) != entity.EntityType {
|
|
return false
|
|
}
|
|
var ent idGetter
|
|
var ok bool
|
|
switch payload.EntityType {
|
|
case dbCommon.RepositoryEntityType:
|
|
if entity.EntityType != params.GithubEntityTypeRepository {
|
|
return false
|
|
}
|
|
ent, ok = payload.Payload.(params.Repository)
|
|
case dbCommon.OrganizationEntityType:
|
|
if entity.EntityType != params.GithubEntityTypeOrganization {
|
|
return false
|
|
}
|
|
ent, ok = payload.Payload.(params.Organization)
|
|
case dbCommon.EnterpriseEntityType:
|
|
if entity.EntityType != params.GithubEntityTypeEnterprise {
|
|
return false
|
|
}
|
|
ent, ok = payload.Payload.(params.Enterprise)
|
|
default:
|
|
return false
|
|
}
|
|
if !ok {
|
|
return false
|
|
}
|
|
return ent.GetID() == entity.ID
|
|
}
|
|
}
|
|
|
|
func WithEntityJobFilter(ghEntity params.GithubEntity) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
switch payload.EntityType {
|
|
case dbCommon.JobEntityType:
|
|
job, ok := payload.Payload.(params.Job)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch ghEntity.EntityType {
|
|
case params.GithubEntityTypeRepository:
|
|
if job.RepoID != nil && job.RepoID.String() != ghEntity.ID {
|
|
return false
|
|
}
|
|
case params.GithubEntityTypeOrganization:
|
|
if job.OrgID != nil && job.OrgID.String() != ghEntity.ID {
|
|
return false
|
|
}
|
|
case params.GithubEntityTypeEnterprise:
|
|
if job.EnterpriseID != nil && job.EnterpriseID.String() != ghEntity.ID {
|
|
return false
|
|
}
|
|
default:
|
|
return false
|
|
}
|
|
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithGithubCredentialsFilter returns a filter function that filters payloads by Github credentials.
|
|
func WithGithubCredentialsFilter(creds params.GithubCredentials) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
if payload.EntityType != dbCommon.GithubCredentialsEntityType {
|
|
return false
|
|
}
|
|
credsPayload, ok := payload.Payload.(params.GithubCredentials)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return credsPayload.ID == creds.ID
|
|
}
|
|
}
|
|
|
|
// WithUserIDFilter returns a filter function that filters payloads by user ID.
|
|
func WithUserIDFilter(userID string) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
if payload.EntityType != dbCommon.UserEntityType {
|
|
return false
|
|
}
|
|
userPayload, ok := payload.Payload.(params.User)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return userPayload.ID == userID
|
|
}
|
|
}
|
|
|
|
// WithNone returns a filter function that always returns false.
|
|
func WithNone() dbCommon.PayloadFilterFunc {
|
|
return func(_ dbCommon.ChangePayload) bool {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// WithEverything returns a filter function that always returns true.
|
|
func WithEverything() dbCommon.PayloadFilterFunc {
|
|
return func(_ dbCommon.ChangePayload) bool {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// WithExcludeEntityTypeFilter returns a filter function that filters payloads by excluding
|
|
// the provided entity type.
|
|
func WithExcludeEntityTypeFilter(entityType dbCommon.DatabaseEntityType) dbCommon.PayloadFilterFunc {
|
|
return func(payload dbCommon.ChangePayload) bool {
|
|
return payload.EntityType != entityType
|
|
}
|
|
}
|