2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2020-10-01 18:43:28 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
2020-11-05 17:06:08 +00:00
|
|
|
memdb "github.com/hashicorp/go-memdb"
|
2020-10-01 18:43:28 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
2020-10-08 18:27:52 +00:00
|
|
|
var MsgTypeEvents = map[structs.MessageType]string{
|
2022-02-28 09:44:58 +00:00
|
|
|
structs.NodeRegisterRequestType: structs.TypeNodeRegistration,
|
|
|
|
structs.NodeDeregisterRequestType: structs.TypeNodeDeregistration,
|
|
|
|
structs.UpsertNodeEventsType: structs.TypeNodeEvent,
|
2023-06-06 14:14:47 +00:00
|
|
|
structs.NodePoolUpsertRequestType: structs.TypeNodePoolUpserted,
|
|
|
|
structs.NodePoolDeleteRequestType: structs.TypeNodePoolDeleted,
|
2022-02-28 09:44:58 +00:00
|
|
|
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,
|
2022-10-20 07:43:35 +00:00
|
|
|
structs.ACLRolesDeleteByIDRequestType: structs.TypeACLRoleDeleted,
|
|
|
|
structs.ACLRolesUpsertRequestType: structs.TypeACLRoleUpserted,
|
2022-11-21 09:06:05 +00:00
|
|
|
structs.ACLAuthMethodsUpsertRequestType: structs.TypeACLAuthMethodUpserted,
|
|
|
|
structs.ACLAuthMethodsDeleteRequestType: structs.TypeACLAuthMethodDeleted,
|
2022-12-14 13:49:49 +00:00
|
|
|
structs.ACLBindingRulesUpsertRequestType: structs.TypeACLBindingRuleUpserted,
|
|
|
|
structs.ACLBindingRulesDeleteRequestType: structs.TypeACLBindingRuleDeleted,
|
2022-02-28 09:44:58 +00:00
|
|
|
structs.ServiceRegistrationUpsertRequestType: structs.TypeServiceRegistration,
|
|
|
|
structs.ServiceRegistrationDeleteByIDRequestType: structs.TypeServiceDeregistration,
|
|
|
|
structs.ServiceRegistrationDeleteByNodeIDRequestType: structs.TypeServiceDeregistration,
|
2020-10-08 18:27:52 +00:00
|
|
|
}
|
|
|
|
|
2020-11-05 21:06:52 +00:00
|
|
|
func eventsFromChanges(tx ReadTxn, changes Changes) *structs.Events {
|
2020-10-08 18:27:52 +00:00
|
|
|
eventType, ok := MsgTypeEvents[changes.MsgType]
|
|
|
|
if !ok {
|
2020-11-05 21:06:52 +00:00
|
|
|
return nil
|
2020-10-02 18:23:30 +00:00
|
|
|
}
|
|
|
|
|
2020-10-04 19:12:35 +00:00
|
|
|
var events []structs.Event
|
2020-10-02 18:23:30 +00:00
|
|
|
for _, change := range changes.Changes {
|
2020-11-05 17:06:08 +00:00
|
|
|
if event, ok := eventFromChange(change); ok {
|
|
|
|
event.Type = eventType
|
|
|
|
event.Index = changes.Index
|
2020-10-02 18:23:30 +00:00
|
|
|
events = append(events, event)
|
2020-11-05 17:06:08 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-02 18:23:30 +00:00
|
|
|
|
2020-11-05 21:06:52 +00:00
|
|
|
return &structs.Events{Index: changes.Index, Events: events}
|
2020-11-05 17:06:08 +00:00
|
|
|
}
|
2020-10-02 20:13:49 +00:00
|
|
|
|
2020-11-05 17:06:08 +00:00
|
|
|
func eventFromChange(change memdb.Change) (structs.Event, bool) {
|
2020-11-05 21:06:52 +00:00
|
|
|
if change.Deleted() {
|
2020-12-01 20:14:05 +00:00
|
|
|
switch change.Table {
|
|
|
|
case "acl_token":
|
|
|
|
before, ok := change.Before.(*structs.ACLToken)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-12-11 15:40:50 +00:00
|
|
|
|
2020-12-01 16:11:34 +00:00
|
|
|
return structs.Event{
|
2020-12-11 15:40:50 +00:00
|
|
|
Topic: structs.TopicACLToken,
|
|
|
|
Key: before.AccessorID,
|
|
|
|
Payload: structs.NewACLTokenEvent(before),
|
2020-12-01 16:11:34 +00:00
|
|
|
}, true
|
2020-12-01 20:14:05 +00:00
|
|
|
case "acl_policy":
|
|
|
|
before, ok := change.Before.(*structs.ACLPolicy)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-12-01 16:11:34 +00:00
|
|
|
return structs.Event{
|
|
|
|
Topic: structs.TopicACLPolicy,
|
|
|
|
Key: before.Name,
|
2020-12-11 15:40:50 +00:00
|
|
|
Payload: &structs.ACLPolicyEvent{
|
2020-12-01 16:11:34 +00:00
|
|
|
ACLPolicy: before,
|
|
|
|
},
|
|
|
|
}, true
|
2022-10-20 07:43:35 +00:00
|
|
|
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
|
2022-11-21 09:06:05 +00:00
|
|
|
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
|
2022-12-14 13:49:49 +00:00
|
|
|
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
|
2020-12-01 20:14:05 +00:00
|
|
|
case "nodes":
|
|
|
|
before, ok := change.Before.(*structs.Node)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-12-03 17:27:14 +00:00
|
|
|
|
2021-03-26 17:03:15 +00:00
|
|
|
before = before.Sanitize()
|
2020-11-05 21:06:52 +00:00
|
|
|
return structs.Event{
|
|
|
|
Topic: structs.TopicNode,
|
2021-02-11 15:40:59 +00:00
|
|
|
Key: before.ID,
|
2020-11-23 19:01:10 +00:00
|
|
|
Payload: &structs.NodeStreamEvent{
|
2021-02-11 15:40:59 +00:00
|
|
|
Node: before,
|
2020-11-05 21:06:52 +00:00
|
|
|
},
|
|
|
|
}, true
|
2023-06-06 14:14:47 +00:00
|
|
|
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
|
2022-02-28 09:44:58 +00:00
|
|
|
case TableServiceRegistrations:
|
|
|
|
before, ok := change.Before.(*structs.ServiceRegistration)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
|
|
|
return structs.Event{
|
2022-04-05 07:25:22 +00:00
|
|
|
Topic: structs.TopicService,
|
2022-02-28 09:44:58 +00:00
|
|
|
Key: before.ID,
|
|
|
|
FilterKeys: []string{
|
|
|
|
before.JobID,
|
|
|
|
before.ServiceName,
|
|
|
|
},
|
|
|
|
Namespace: before.Namespace,
|
|
|
|
Payload: &structs.ServiceRegistrationStreamEvent{
|
|
|
|
Service: before,
|
|
|
|
},
|
|
|
|
}, true
|
2020-11-05 21:06:52 +00:00
|
|
|
}
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
|
|
|
|
2020-12-01 20:14:05 +00:00
|
|
|
switch change.Table {
|
|
|
|
case "acl_token":
|
|
|
|
after, ok := change.After.(*structs.ACLToken)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-12-11 15:40:50 +00:00
|
|
|
|
2020-12-01 16:11:34 +00:00
|
|
|
return structs.Event{
|
2020-12-11 15:40:50 +00:00
|
|
|
Topic: structs.TopicACLToken,
|
|
|
|
Key: after.AccessorID,
|
|
|
|
Payload: structs.NewACLTokenEvent(after),
|
2020-12-01 16:11:34 +00:00
|
|
|
}, true
|
2020-12-01 20:14:05 +00:00
|
|
|
case "acl_policy":
|
|
|
|
after, ok := change.After.(*structs.ACLPolicy)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-12-01 16:11:34 +00:00
|
|
|
return structs.Event{
|
|
|
|
Topic: structs.TopicACLPolicy,
|
|
|
|
Key: after.Name,
|
2020-12-11 15:40:50 +00:00
|
|
|
Payload: &structs.ACLPolicyEvent{
|
2020-12-01 16:11:34 +00:00
|
|
|
ACLPolicy: after,
|
|
|
|
},
|
|
|
|
}, true
|
2022-10-20 07:43:35 +00:00
|
|
|
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
|
2022-11-21 09:06:05 +00:00
|
|
|
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
|
2022-12-14 13:49:49 +00:00
|
|
|
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
|
2020-12-01 20:14:05 +00:00
|
|
|
case "evals":
|
|
|
|
after, ok := change.After.(*structs.Evaluation)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-11-05 17:06:08 +00:00
|
|
|
return structs.Event{
|
2020-12-03 16:48:18 +00:00
|
|
|
Topic: structs.TopicEvaluation,
|
2020-11-05 17:06:08 +00:00
|
|
|
Key: after.ID,
|
|
|
|
FilterKeys: []string{
|
|
|
|
after.JobID,
|
|
|
|
after.DeploymentID,
|
|
|
|
},
|
|
|
|
Namespace: after.Namespace,
|
2020-12-03 16:48:18 +00:00
|
|
|
Payload: &structs.EvaluationEvent{
|
|
|
|
Evaluation: after,
|
2020-11-05 17:06:08 +00:00
|
|
|
},
|
|
|
|
}, true
|
2020-12-01 20:14:05 +00:00
|
|
|
case "allocs":
|
|
|
|
after, ok := change.After.(*structs.Allocation)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-11-05 17:06:08 +00:00
|
|
|
alloc := after.Copy()
|
|
|
|
|
|
|
|
filterKeys := []string{
|
|
|
|
alloc.JobID,
|
|
|
|
alloc.DeploymentID,
|
2020-10-02 18:23:30 +00:00
|
|
|
}
|
2020-11-05 17:06:08 +00:00
|
|
|
|
|
|
|
// remove job info to help keep size of alloc event down
|
|
|
|
alloc.Job = nil
|
|
|
|
|
|
|
|
return structs.Event{
|
2020-12-03 16:48:18 +00:00
|
|
|
Topic: structs.TopicAllocation,
|
2020-11-05 17:06:08 +00:00
|
|
|
Key: after.ID,
|
|
|
|
FilterKeys: filterKeys,
|
|
|
|
Namespace: after.Namespace,
|
2020-12-03 16:48:18 +00:00
|
|
|
Payload: &structs.AllocationEvent{
|
|
|
|
Allocation: alloc,
|
2020-11-05 17:06:08 +00:00
|
|
|
},
|
|
|
|
}, true
|
2020-12-01 20:14:05 +00:00
|
|
|
case "jobs":
|
|
|
|
after, ok := change.After.(*structs.Job)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-11-05 17:06:08 +00:00
|
|
|
return structs.Event{
|
|
|
|
Topic: structs.TopicJob,
|
|
|
|
Key: after.ID,
|
|
|
|
Namespace: after.Namespace,
|
2020-11-23 19:01:10 +00:00
|
|
|
Payload: &structs.JobEvent{
|
2020-11-05 17:06:08 +00:00
|
|
|
Job: after,
|
|
|
|
},
|
|
|
|
}, true
|
2020-12-01 20:14:05 +00:00
|
|
|
case "nodes":
|
|
|
|
after, ok := change.After.(*structs.Node)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-12-03 17:27:14 +00:00
|
|
|
|
2021-03-26 17:03:15 +00:00
|
|
|
after = after.Sanitize()
|
2020-11-05 17:06:08 +00:00
|
|
|
return structs.Event{
|
|
|
|
Topic: structs.TopicNode,
|
2021-02-11 15:40:59 +00:00
|
|
|
Key: after.ID,
|
2020-11-23 19:01:10 +00:00
|
|
|
Payload: &structs.NodeStreamEvent{
|
2021-02-11 15:40:59 +00:00
|
|
|
Node: after,
|
2020-11-05 17:06:08 +00:00
|
|
|
},
|
|
|
|
}, true
|
2023-06-06 14:14:47 +00:00
|
|
|
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
|
2020-12-01 20:14:05 +00:00
|
|
|
case "deployment":
|
|
|
|
after, ok := change.After.(*structs.Deployment)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
2020-11-05 17:06:08 +00:00
|
|
|
return structs.Event{
|
|
|
|
Topic: structs.TopicDeployment,
|
|
|
|
Key: after.ID,
|
|
|
|
Namespace: after.Namespace,
|
|
|
|
FilterKeys: []string{after.JobID},
|
2020-11-23 19:01:10 +00:00
|
|
|
Payload: &structs.DeploymentEvent{
|
2020-11-05 17:06:08 +00:00
|
|
|
Deployment: after,
|
|
|
|
},
|
|
|
|
}, true
|
2022-02-28 09:44:58 +00:00
|
|
|
case TableServiceRegistrations:
|
|
|
|
after, ok := change.After.(*structs.ServiceRegistration)
|
|
|
|
if !ok {
|
|
|
|
return structs.Event{}, false
|
|
|
|
}
|
|
|
|
return structs.Event{
|
2022-04-05 07:25:22 +00:00
|
|
|
Topic: structs.TopicService,
|
2022-02-28 09:44:58 +00:00
|
|
|
Key: after.ID,
|
|
|
|
FilterKeys: []string{
|
|
|
|
after.JobID,
|
|
|
|
after.ServiceName,
|
|
|
|
},
|
|
|
|
Namespace: after.Namespace,
|
|
|
|
Payload: &structs.ServiceRegistrationStreamEvent{
|
|
|
|
Service: after,
|
|
|
|
},
|
|
|
|
}, true
|
2020-10-02 18:23:30 +00:00
|
|
|
}
|
|
|
|
|
2020-11-05 17:06:08 +00:00
|
|
|
return structs.Event{}, false
|
2020-10-02 18:23:30 +00:00
|
|
|
}
|