// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package state import ( memdb "github.com/hashicorp/go-memdb" "github.com/hashicorp/nomad/nomad/structs" ) var MsgTypeEvents = map[structs.MessageType]string{ structs.NodeRegisterRequestType: structs.TypeNodeRegistration, structs.NodeDeregisterRequestType: structs.TypeNodeDeregistration, structs.UpsertNodeEventsType: structs.TypeNodeEvent, structs.NodePoolUpsertRequestType: structs.TypeNodePoolUpserted, structs.NodePoolDeleteRequestType: structs.TypeNodePoolDeleted, structs.EvalUpdateRequestType: structs.TypeEvalUpdated, structs.AllocClientUpdateRequestType: structs.TypeAllocationUpdated, structs.JobRegisterRequestType: structs.TypeJobRegistered, structs.NodeUpdateStatusRequestType: structs.TypeNodeEvent, structs.JobDeregisterRequestType: structs.TypeJobDeregistered, structs.JobBatchDeregisterRequestType: structs.TypeJobBatchDeregistered, structs.AllocUpdateDesiredTransitionRequestType: structs.TypeAllocationUpdateDesiredStatus, structs.NodeUpdateEligibilityRequestType: structs.TypeNodeDrain, structs.NodeUpdateDrainRequestType: structs.TypeNodeDrain, structs.BatchNodeUpdateDrainRequestType: structs.TypeNodeDrain, structs.DeploymentStatusUpdateRequestType: structs.TypeDeploymentUpdate, structs.DeploymentPromoteRequestType: structs.TypeDeploymentPromotion, structs.DeploymentAllocHealthRequestType: structs.TypeDeploymentAllocHealth, structs.ApplyPlanResultsRequestType: structs.TypePlanResult, structs.ACLTokenDeleteRequestType: structs.TypeACLTokenDeleted, structs.ACLTokenUpsertRequestType: structs.TypeACLTokenUpserted, structs.ACLPolicyDeleteRequestType: structs.TypeACLPolicyDeleted, structs.ACLPolicyUpsertRequestType: structs.TypeACLPolicyUpserted, structs.ACLRolesDeleteByIDRequestType: structs.TypeACLRoleDeleted, structs.ACLRolesUpsertRequestType: structs.TypeACLRoleUpserted, structs.ACLAuthMethodsUpsertRequestType: structs.TypeACLAuthMethodUpserted, structs.ACLAuthMethodsDeleteRequestType: structs.TypeACLAuthMethodDeleted, structs.ACLBindingRulesUpsertRequestType: structs.TypeACLBindingRuleUpserted, structs.ACLBindingRulesDeleteRequestType: structs.TypeACLBindingRuleDeleted, structs.ServiceRegistrationUpsertRequestType: structs.TypeServiceRegistration, structs.ServiceRegistrationDeleteByIDRequestType: structs.TypeServiceDeregistration, structs.ServiceRegistrationDeleteByNodeIDRequestType: structs.TypeServiceDeregistration, } func eventsFromChanges(tx ReadTxn, changes Changes) *structs.Events { eventType, ok := MsgTypeEvents[changes.MsgType] if !ok { return nil } var events []structs.Event for _, change := range changes.Changes { if event, ok := eventFromChange(change); ok { event.Type = eventType event.Index = changes.Index events = append(events, event) } } return &structs.Events{Index: changes.Index, Events: events} } func eventFromChange(change memdb.Change) (structs.Event, bool) { if change.Deleted() { switch change.Table { case "acl_token": before, ok := change.Before.(*structs.ACLToken) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLToken, Key: before.AccessorID, Payload: structs.NewACLTokenEvent(before), }, true case "acl_policy": before, ok := change.Before.(*structs.ACLPolicy) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLPolicy, Key: before.Name, Payload: &structs.ACLPolicyEvent{ ACLPolicy: before, }, }, true case TableACLRoles: before, ok := change.Before.(*structs.ACLRole) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLRole, Key: before.ID, FilterKeys: []string{before.Name}, Payload: &structs.ACLRoleStreamEvent{ ACLRole: before, }, }, true case TableACLAuthMethods: before, ok := change.Before.(*structs.ACLAuthMethod) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLAuthMethod, Key: before.Name, Payload: &structs.ACLAuthMethodEvent{ AuthMethod: before, }, }, true case TableACLBindingRules: before, ok := change.Before.(*structs.ACLBindingRule) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLBindingRule, Key: before.ID, FilterKeys: []string{before.AuthMethod}, Payload: &structs.ACLBindingRuleEvent{ ACLBindingRule: before, }, }, true case "nodes": before, ok := change.Before.(*structs.Node) if !ok { return structs.Event{}, false } before = before.Sanitize() return structs.Event{ Topic: structs.TopicNode, Key: before.ID, Payload: &structs.NodeStreamEvent{ Node: before, }, }, true case TableNodePools: before, ok := change.Before.(*structs.NodePool) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicNodePool, Key: before.Name, Payload: &structs.NodePoolEvent{ NodePool: before, }, }, true case TableServiceRegistrations: before, ok := change.Before.(*structs.ServiceRegistration) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicService, Key: before.ID, FilterKeys: []string{ before.JobID, before.ServiceName, }, Namespace: before.Namespace, Payload: &structs.ServiceRegistrationStreamEvent{ Service: before, }, }, true } return structs.Event{}, false } switch change.Table { case "acl_token": after, ok := change.After.(*structs.ACLToken) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLToken, Key: after.AccessorID, Payload: structs.NewACLTokenEvent(after), }, true case "acl_policy": after, ok := change.After.(*structs.ACLPolicy) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLPolicy, Key: after.Name, Payload: &structs.ACLPolicyEvent{ ACLPolicy: after, }, }, true case TableACLRoles: after, ok := change.After.(*structs.ACLRole) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLRole, Key: after.ID, FilterKeys: []string{after.Name}, Payload: &structs.ACLRoleStreamEvent{ ACLRole: after, }, }, true case TableACLAuthMethods: after, ok := change.After.(*structs.ACLAuthMethod) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLAuthMethod, Key: after.Name, Payload: &structs.ACLAuthMethodEvent{ AuthMethod: after, }, }, true case TableACLBindingRules: after, ok := change.After.(*structs.ACLBindingRule) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicACLBindingRule, Key: after.ID, FilterKeys: []string{after.AuthMethod}, Payload: &structs.ACLBindingRuleEvent{ ACLBindingRule: after, }, }, true case "evals": after, ok := change.After.(*structs.Evaluation) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicEvaluation, Key: after.ID, FilterKeys: []string{ after.JobID, after.DeploymentID, }, Namespace: after.Namespace, Payload: &structs.EvaluationEvent{ Evaluation: after, }, }, true case "allocs": after, ok := change.After.(*structs.Allocation) if !ok { return structs.Event{}, false } alloc := after.Copy() filterKeys := []string{ alloc.JobID, alloc.DeploymentID, } // remove job info to help keep size of alloc event down alloc.Job = nil return structs.Event{ Topic: structs.TopicAllocation, Key: after.ID, FilterKeys: filterKeys, Namespace: after.Namespace, Payload: &structs.AllocationEvent{ Allocation: alloc, }, }, true case "jobs": after, ok := change.After.(*structs.Job) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicJob, Key: after.ID, Namespace: after.Namespace, Payload: &structs.JobEvent{ Job: after, }, }, true case "nodes": after, ok := change.After.(*structs.Node) if !ok { return structs.Event{}, false } after = after.Sanitize() return structs.Event{ Topic: structs.TopicNode, Key: after.ID, Payload: &structs.NodeStreamEvent{ Node: after, }, }, true case TableNodePools: after, ok := change.After.(*structs.NodePool) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicNodePool, Key: after.Name, Payload: &structs.NodePoolEvent{ NodePool: after, }, }, true case "deployment": after, ok := change.After.(*structs.Deployment) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicDeployment, Key: after.ID, Namespace: after.Namespace, FilterKeys: []string{after.JobID}, Payload: &structs.DeploymentEvent{ Deployment: after, }, }, true case TableServiceRegistrations: after, ok := change.After.(*structs.ServiceRegistration) if !ok { return structs.Event{}, false } return structs.Event{ Topic: structs.TopicService, Key: after.ID, FilterKeys: []string{ after.JobID, after.ServiceName, }, Namespace: after.Namespace, Payload: &structs.ServiceRegistrationStreamEvent{ Service: after, }, }, true } return structs.Event{}, false }