open-consul/agent/consul/gateways/bind.go

76 lines
2.9 KiB
Go

package gateways
import (
"errors"
"github.com/hashicorp/consul/agent/configentry"
"github.com/hashicorp/consul/agent/structs"
)
// referenceSet stores an O(1) accessible set of ResourceReference objects.
type referenceSet = map[structs.ResourceReference]any
// gatewayRefs maps a gateway kind/name to a set of resource references.
type gatewayRefs = map[configentry.KindName][]structs.ResourceReference
// BindRoutesToGateways takes a slice of bound API gateways and a variadic number of routes.
// It iterates over the parent references for each route. These parents are gateways the
// route should be bound to. If the parent matches a bound gateway, the route is bound to the
// gateway. Otherwise, the route is unbound from the gateway if it was previously bound.
//
// The function returns a list of references to the modified BoundAPIGatewayConfigEntry objects,
// a map of resource references to errors that occurred when they were attempted to be
// bound to a gateway.
func BindRoutesToGateways(gateways []*structs.BoundAPIGatewayConfigEntry, routes ...structs.BoundRoute) ([]*structs.BoundAPIGatewayConfigEntry, map[structs.ResourceReference]error) {
modified := make([]*structs.BoundAPIGatewayConfigEntry, 0, len(gateways))
// errored stores the errors from events where a resource reference failed to bind to a gateway.
errored := make(map[structs.ResourceReference]error)
for _, route := range routes {
parentRefs, gatewayRefs := getReferences(route)
// Iterate over all BoundAPIGateway config entries and try to bind them to the route if they are a parent.
for _, gateway := range gateways {
references, routeReferencesGateway := gatewayRefs[configentry.NewKindNameForEntry(gateway)]
if routeReferencesGateway {
didUpdate, errors := gateway.UpdateRouteBinding(references, route)
if didUpdate {
modified = append(modified, gateway)
}
for ref, err := range errors {
errored[ref] = err
}
for _, ref := range references {
delete(parentRefs, ref)
}
} else {
if gateway.UnbindRoute(route) {
modified = append(modified, gateway)
}
}
}
// Add all references that aren't bound at this point to the error set.
for reference := range parentRefs {
errored[reference] = errors.New("invalid reference to missing parent")
}
}
return modified, errored
}
// getReferences returns a set of all the resource references for a given route as well as
// a map of gateway kind/name to a list of resource references for that gateway.
func getReferences(route structs.BoundRoute) (referenceSet, gatewayRefs) {
parentRefs := make(referenceSet)
gatewayRefs := make(gatewayRefs)
for _, ref := range route.GetParents() {
parentRefs[ref] = struct{}{}
kindName := configentry.NewKindName(structs.BoundAPIGateway, ref.Name, &ref.EnterpriseMeta)
gatewayRefs[kindName] = append(gatewayRefs[kindName], ref)
}
return parentRefs, gatewayRefs
}