2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 18:39:22 +00:00
|
|
|
|
2022-07-08 17:01:13 +00:00
|
|
|
package peerstream
|
2022-05-19 21:37:52 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
|
|
"github.com/hashicorp/consul/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
// healthSnapshot represents a normalized view of a set of CheckServiceNodes
|
|
|
|
// meant for easy comparison to aid in differential synchronization
|
|
|
|
type healthSnapshot struct {
|
2022-07-15 14:51:38 +00:00
|
|
|
// Nodes is a map of a node name to a nodeSnapshot. Ideally we would be able to use
|
|
|
|
// the types.NodeID and assume they are UUIDs for the map key but Consul doesn't
|
|
|
|
// require a NodeID. Therefore we must key off of the only bit of ID material
|
|
|
|
// that is required which is the node name.
|
|
|
|
Nodes map[string]*nodeSnapshot
|
2022-05-19 21:37:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type nodeSnapshot struct {
|
|
|
|
Node *structs.Node
|
|
|
|
Services map[structs.ServiceID]*serviceSnapshot
|
|
|
|
}
|
|
|
|
|
|
|
|
type serviceSnapshot struct {
|
|
|
|
Service *structs.NodeService
|
|
|
|
Checks map[types.CheckID]*structs.HealthCheck
|
|
|
|
}
|
|
|
|
|
|
|
|
func newHealthSnapshot(all []structs.CheckServiceNode, partition, peerName string) *healthSnapshot {
|
|
|
|
// For all nodes, services, and checks we override the peer name and
|
|
|
|
// partition to be the local partition and local name for the peer.
|
|
|
|
for _, instance := range all {
|
|
|
|
instance.Node.PeerName = peerName
|
|
|
|
instance.Node.OverridePartition(partition)
|
|
|
|
|
|
|
|
instance.Service.PeerName = peerName
|
|
|
|
instance.Service.OverridePartition(partition)
|
|
|
|
|
|
|
|
for _, chk := range instance.Checks {
|
|
|
|
chk.PeerName = peerName
|
|
|
|
chk.OverridePartition(partition)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
snap := &healthSnapshot{
|
2022-07-15 14:51:38 +00:00
|
|
|
Nodes: make(map[string]*nodeSnapshot),
|
2022-05-19 21:37:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, instance := range all {
|
2022-07-15 14:51:38 +00:00
|
|
|
if instance.Node.Node == "" {
|
|
|
|
panic("TODO(peering): data should always have a node name")
|
2022-05-19 21:37:52 +00:00
|
|
|
}
|
2022-07-15 14:51:38 +00:00
|
|
|
nodeSnap, ok := snap.Nodes[instance.Node.Node]
|
2022-05-19 21:37:52 +00:00
|
|
|
if !ok {
|
|
|
|
nodeSnap = &nodeSnapshot{
|
|
|
|
Node: instance.Node,
|
|
|
|
Services: make(map[structs.ServiceID]*serviceSnapshot),
|
|
|
|
}
|
2022-07-15 14:51:38 +00:00
|
|
|
snap.Nodes[instance.Node.Node] = nodeSnap
|
2022-05-19 21:37:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if instance.Service.ID == "" {
|
|
|
|
panic("TODO(peering): data should always have a service ID")
|
|
|
|
}
|
|
|
|
sid := instance.Service.CompoundServiceID()
|
|
|
|
|
|
|
|
svcSnap, ok := nodeSnap.Services[sid]
|
|
|
|
if !ok {
|
|
|
|
svcSnap = &serviceSnapshot{
|
|
|
|
Service: instance.Service,
|
|
|
|
Checks: make(map[types.CheckID]*structs.HealthCheck),
|
|
|
|
}
|
|
|
|
nodeSnap.Services[sid] = svcSnap
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range instance.Checks {
|
|
|
|
if c.CheckID == "" {
|
|
|
|
panic("TODO(peering): data should always have a check ID")
|
|
|
|
}
|
|
|
|
svcSnap.Checks[c.CheckID] = c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return snap
|
|
|
|
}
|