mirror of https://github.com/status-im/consul.git
Match route and listener protocols when binding (#16057)
* Add GatewayMeta for matching routes to listeners based on protocols
* Add GetGatewayMeta
* Apply suggestions from code review
Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com>
* Make GatewayMeta private
* Bound -> BoundGateway
* Document gatewayMeta more
* Simplify conditional
* Parallelize tests and simplify bind conditional
* gofmt
* 💧 getGatewayMeta
---------
Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com>
This commit is contained in:
parent
a1498b015d
commit
7814471159
|
@ -21,7 +21,7 @@ type gatewayRefs = map[configentry.KindName][]structs.ResourceReference
|
||||||
// The function returns a list of references to the modified BoundAPIGatewayConfigEntry objects,
|
// 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
|
// a map of resource references to errors that occurred when they were attempted to be
|
||||||
// bound to a gateway.
|
// bound to a gateway.
|
||||||
func BindRoutesToGateways(gateways []*structs.BoundAPIGatewayConfigEntry, routes ...structs.BoundRoute) ([]*structs.BoundAPIGatewayConfigEntry, map[structs.ResourceReference]error) {
|
func BindRoutesToGateways(gateways []*gatewayMeta, routes ...structs.BoundRoute) ([]*structs.BoundAPIGatewayConfigEntry, map[structs.ResourceReference]error) {
|
||||||
modified := make([]*structs.BoundAPIGatewayConfigEntry, 0, len(gateways))
|
modified := make([]*structs.BoundAPIGatewayConfigEntry, 0, len(gateways))
|
||||||
|
|
||||||
// errored stores the errors from events where a resource reference failed to bind to a gateway.
|
// errored stores the errors from events where a resource reference failed to bind to a gateway.
|
||||||
|
@ -32,11 +32,11 @@ func BindRoutesToGateways(gateways []*structs.BoundAPIGatewayConfigEntry, routes
|
||||||
|
|
||||||
// Iterate over all BoundAPIGateway config entries and try to bind them to the route if they are a parent.
|
// Iterate over all BoundAPIGateway config entries and try to bind them to the route if they are a parent.
|
||||||
for _, gateway := range gateways {
|
for _, gateway := range gateways {
|
||||||
references, routeReferencesGateway := gatewayRefs[configentry.NewKindNameForEntry(gateway)]
|
references, routeReferencesGateway := gatewayRefs[configentry.NewKindNameForEntry(gateway.BoundGateway)]
|
||||||
if routeReferencesGateway {
|
if routeReferencesGateway {
|
||||||
didUpdate, errors := gateway.UpdateRouteBinding(references, route)
|
didUpdate, errors := gateway.updateRouteBinding(references, route)
|
||||||
if didUpdate {
|
if didUpdate {
|
||||||
modified = append(modified, gateway)
|
modified = append(modified, gateway.BoundGateway)
|
||||||
}
|
}
|
||||||
for ref, err := range errors {
|
for ref, err := range errors {
|
||||||
errored[ref] = err
|
errored[ref] = err
|
||||||
|
@ -44,10 +44,8 @@ func BindRoutesToGateways(gateways []*structs.BoundAPIGatewayConfigEntry, routes
|
||||||
for _, ref := range references {
|
for _, ref := range references {
|
||||||
delete(parentRefs, ref)
|
delete(parentRefs, ref)
|
||||||
}
|
}
|
||||||
} else {
|
} else if gateway.unbindRoute(route) {
|
||||||
if gateway.UnbindRoute(route) {
|
modified = append(modified, gateway.BoundGateway)
|
||||||
modified = append(modified, gateway)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,139 @@
|
||||||
|
package gateways
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// gatewayMeta embeds both a BoundAPIGateway and its corresponding APIGateway.
|
||||||
|
// This is used when binding routes to a gateway to ensure that a route's protocol (e.g. http)
|
||||||
|
// matches the protocol of the listener it wants to bind to. The binding modifies the
|
||||||
|
// "bound" gateway, but relies on the "gateway" to determine the protocol of the listener.
|
||||||
|
type gatewayMeta struct {
|
||||||
|
// BoundGateway is the bound-api-gateway config entry for a given gateway.
|
||||||
|
BoundGateway *structs.BoundAPIGatewayConfigEntry
|
||||||
|
// Gateway is the api-gateway config entry for the gateway.
|
||||||
|
Gateway *structs.APIGatewayConfigEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateRouteBinding takes a parent resource reference and a BoundRoute and
|
||||||
|
// modifies the listeners on the BoundAPIGateway config entry in GatewayMeta
|
||||||
|
// to reflect the binding of the route to the gateway.
|
||||||
|
//
|
||||||
|
// If the reference is not valid or the route's protocol does not match the
|
||||||
|
// targeted listener's protocol, a mapping of parent references to associated
|
||||||
|
// errors is returned.
|
||||||
|
func (g *gatewayMeta) updateRouteBinding(refs []structs.ResourceReference, route structs.BoundRoute) (bool, map[structs.ResourceReference]error) {
|
||||||
|
if g.BoundGateway == nil || g.Gateway == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
didUpdate := false
|
||||||
|
errors := make(map[structs.ResourceReference]error)
|
||||||
|
|
||||||
|
if len(g.BoundGateway.Listeners) == 0 {
|
||||||
|
for _, ref := range refs {
|
||||||
|
errors[ref] = fmt.Errorf("route cannot bind because gateway has no listeners")
|
||||||
|
}
|
||||||
|
return false, errors
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, listener := range g.BoundGateway.Listeners {
|
||||||
|
// Unbind to handle any stale route references.
|
||||||
|
didUnbind := listener.UnbindRoute(route)
|
||||||
|
if didUnbind {
|
||||||
|
didUpdate = true
|
||||||
|
}
|
||||||
|
g.BoundGateway.Listeners[i] = listener
|
||||||
|
|
||||||
|
for _, ref := range refs {
|
||||||
|
didBind, err := g.bindRoute(ref, route)
|
||||||
|
if err != nil {
|
||||||
|
errors[ref] = err
|
||||||
|
}
|
||||||
|
if didBind {
|
||||||
|
didUpdate = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return didUpdate, errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindRoute takes a parent reference and a route and attempts to bind the route to the
|
||||||
|
// bound gateway in the gatewayMeta struct. It returns true if the route was bound and
|
||||||
|
// false if it was not. If the route fails to bind, an error is returned.
|
||||||
|
//
|
||||||
|
// Binding logic binds a route to one or more listeners on the Bound gateway.
|
||||||
|
// For a route to successfully bind it must:
|
||||||
|
// - have a parent reference to the gateway
|
||||||
|
// - have a parent reference with a section name matching the name of a listener
|
||||||
|
// on the gateway. If the section name is `""`, the route will be bound to all
|
||||||
|
// listeners on the gateway whose protocol matches the route's protocol.
|
||||||
|
// - have a protocol that matches the protocol of the listener it is being bound to.
|
||||||
|
func (g *gatewayMeta) bindRoute(ref structs.ResourceReference, route structs.BoundRoute) (bool, error) {
|
||||||
|
if g.BoundGateway == nil || g.Gateway == nil {
|
||||||
|
return false, fmt.Errorf("gateway cannot be found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.Kind != structs.APIGateway || g.Gateway.Name != ref.Name || !g.Gateway.EnterpriseMeta.IsSame(&ref.EnterpriseMeta) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(g.BoundGateway.Listeners) == 0 {
|
||||||
|
return false, fmt.Errorf("route cannot bind because gateway has no listeners")
|
||||||
|
}
|
||||||
|
|
||||||
|
didBind := false
|
||||||
|
for _, listener := range g.Gateway.Listeners {
|
||||||
|
// A route with a section name of "" is bound to all listeners on the gateway.
|
||||||
|
if listener.Name != ref.SectionName && ref.SectionName != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if listener.Protocol == route.GetProtocol() {
|
||||||
|
i, boundListener := g.boundListenerByName(listener.Name)
|
||||||
|
if boundListener != nil && boundListener.BindRoute(route) {
|
||||||
|
didBind = true
|
||||||
|
g.BoundGateway.Listeners[i] = *boundListener
|
||||||
|
}
|
||||||
|
} else if ref.SectionName != "" {
|
||||||
|
// Failure to bind to a specific listener is an error
|
||||||
|
return false, fmt.Errorf("failed to bind route %s to gateway %s: listener %s is not a %s listener", route.GetName(), g.Gateway.Name, listener.Name, route.GetProtocol())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !didBind {
|
||||||
|
return didBind, fmt.Errorf("failed to bind route %s to gateway %s: no valid listener has name '%s' and uses %s protocol", route.GetName(), g.Gateway.Name, ref.SectionName, route.GetProtocol())
|
||||||
|
}
|
||||||
|
|
||||||
|
return didBind, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// unbindRoute takes a route and unbinds it from all of the listeners on a gateway.
|
||||||
|
// It returns true if the route was unbound and false if it was not.
|
||||||
|
func (g *gatewayMeta) unbindRoute(route structs.BoundRoute) bool {
|
||||||
|
if g.BoundGateway == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
didUnbind := false
|
||||||
|
for i, listener := range g.BoundGateway.Listeners {
|
||||||
|
if listener.UnbindRoute(route) {
|
||||||
|
didUnbind = true
|
||||||
|
g.BoundGateway.Listeners[i] = listener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return didUnbind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *gatewayMeta) boundListenerByName(name string) (int, *structs.BoundAPIGatewayListener) {
|
||||||
|
for i, listener := range g.BoundGateway.Listeners {
|
||||||
|
if listener.Name == name {
|
||||||
|
return i, &listener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, nil
|
||||||
|
}
|
|
@ -0,0 +1,373 @@
|
||||||
|
package gateways
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBoundAPIGatewayBindRoute(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := map[string]struct {
|
||||||
|
gateway gatewayMeta
|
||||||
|
route structs.BoundRoute
|
||||||
|
expectedBoundGateway structs.BoundAPIGatewayConfigEntry
|
||||||
|
expectedDidBind bool
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
"Bind TCP Route to Gateway": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Gateway: &structs.APIGatewayConfigEntry{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.APIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Protocol: structs.ListenerProtocolTCP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
SectionName: "Listener",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedBoundGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Routes: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDidBind: true,
|
||||||
|
},
|
||||||
|
"Bind TCP Route with wildcard section name to all listeners on Gateway": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener 1",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Listener 2",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Listener 3",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Gateway: &structs.APIGatewayConfigEntry{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.APIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener 1",
|
||||||
|
Protocol: structs.ListenerProtocolTCP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Listener 2",
|
||||||
|
Protocol: structs.ListenerProtocolTCP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Listener 3",
|
||||||
|
Protocol: structs.ListenerProtocolTCP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedBoundGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener 1",
|
||||||
|
Routes: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Listener 2",
|
||||||
|
Routes: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Listener 3",
|
||||||
|
Routes: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDidBind: true,
|
||||||
|
},
|
||||||
|
"TCP Route cannot bind to Gateway because the parent reference kind is not APIGateway": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{},
|
||||||
|
},
|
||||||
|
Gateway: &structs.APIGatewayConfigEntry{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.APIGatewayListener{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Name: "Gateway",
|
||||||
|
SectionName: "Listener",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedBoundGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.TerminatingGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{},
|
||||||
|
},
|
||||||
|
expectedDidBind: false,
|
||||||
|
expectedErr: nil,
|
||||||
|
},
|
||||||
|
"TCP Route cannot bind to Gateway because the parent reference name does not match": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{},
|
||||||
|
},
|
||||||
|
Gateway: &structs.APIGatewayConfigEntry{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.APIGatewayListener{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Other Gateway",
|
||||||
|
SectionName: "Listener",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedBoundGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{},
|
||||||
|
},
|
||||||
|
expectedDidBind: false,
|
||||||
|
expectedErr: nil,
|
||||||
|
},
|
||||||
|
"TCP Route cannot bind to Gateway because it lacks listeners": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{},
|
||||||
|
},
|
||||||
|
Gateway: &structs.APIGatewayConfigEntry{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.APIGatewayListener{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
SectionName: "Listener",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedBoundGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{},
|
||||||
|
},
|
||||||
|
expectedDidBind: false,
|
||||||
|
expectedErr: fmt.Errorf("route cannot bind because gateway has no listeners"),
|
||||||
|
},
|
||||||
|
"TCP Route cannot bind to Gateway because it has an invalid section name": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Gateway: &structs.APIGatewayConfigEntry{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.APIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Protocol: structs.ListenerProtocolTCP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.APIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
SectionName: "Other Listener",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedBoundGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDidBind: false,
|
||||||
|
expectedErr: fmt.Errorf("failed to bind route Route to gateway Gateway: no valid listener has name 'Other Listener' and uses tcp protocol"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range cases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
ref := tc.route.GetParents()[0]
|
||||||
|
|
||||||
|
actualDidBind, actualErr := tc.gateway.bindRoute(ref, tc.route)
|
||||||
|
|
||||||
|
require.Equal(t, tc.expectedDidBind, actualDidBind)
|
||||||
|
require.Equal(t, tc.expectedErr, actualErr)
|
||||||
|
require.Equal(t, tc.expectedBoundGateway.Listeners, tc.gateway.BoundGateway.Listeners)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoundAPIGatewayUnbindRoute(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := map[string]struct {
|
||||||
|
gateway gatewayMeta
|
||||||
|
route structs.BoundRoute
|
||||||
|
expectedGateway structs.BoundAPIGatewayConfigEntry
|
||||||
|
expectedDidUnbind bool
|
||||||
|
}{
|
||||||
|
"TCP Route unbinds from Gateway": {
|
||||||
|
gateway: gatewayMeta{
|
||||||
|
BoundGateway: &structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Routes: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
route: &structs.TCPRouteConfigEntry{
|
||||||
|
Kind: structs.TCPRoute,
|
||||||
|
Name: "Route",
|
||||||
|
Parents: []structs.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
SectionName: "Listener",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedGateway: structs.BoundAPIGatewayConfigEntry{
|
||||||
|
Kind: structs.BoundAPIGateway,
|
||||||
|
Name: "Gateway",
|
||||||
|
Listeners: []structs.BoundAPIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "Listener",
|
||||||
|
Routes: []structs.ResourceReference{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDidUnbind: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range cases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
actualDidUnbind := tc.gateway.unbindRoute(tc.route)
|
||||||
|
|
||||||
|
require.Equal(t, tc.expectedDidUnbind, actualDidUnbind)
|
||||||
|
require.Equal(t, tc.expectedGateway.Listeners, tc.gateway.BoundGateway.Listeners)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -980,77 +980,6 @@ func (e *BoundAPIGatewayConfigEntry) GetEnterpriseMeta() *acl.EnterpriseMeta {
|
||||||
return &e.EnterpriseMeta
|
return &e.EnterpriseMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BoundAPIGatewayConfigEntry) UpdateRouteBinding(refs []ResourceReference, route BoundRoute) (bool, map[ResourceReference]error) {
|
|
||||||
didUpdate := false
|
|
||||||
errors := make(map[ResourceReference]error)
|
|
||||||
|
|
||||||
if len(e.Listeners) == 0 {
|
|
||||||
for _, ref := range refs {
|
|
||||||
errors[ref] = fmt.Errorf("route cannot bind because gateway has no listeners")
|
|
||||||
}
|
|
||||||
return false, errors
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, listener := range e.Listeners {
|
|
||||||
// Unbind to handle any stale route references.
|
|
||||||
didUnbind := listener.UnbindRoute(route)
|
|
||||||
if didUnbind {
|
|
||||||
didUpdate = true
|
|
||||||
}
|
|
||||||
e.Listeners[i] = listener
|
|
||||||
|
|
||||||
for _, ref := range refs {
|
|
||||||
didBind, err := e.BindRoute(ref, route)
|
|
||||||
if err != nil {
|
|
||||||
errors[ref] = err
|
|
||||||
}
|
|
||||||
if didBind {
|
|
||||||
didUpdate = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return didUpdate, errors
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *BoundAPIGatewayConfigEntry) BindRoute(ref ResourceReference, route BoundRoute) (bool, error) {
|
|
||||||
if ref.Kind != APIGateway || e.Name != ref.Name || !e.EnterpriseMeta.IsSame(&ref.EnterpriseMeta) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(e.Listeners) == 0 {
|
|
||||||
return false, fmt.Errorf("route cannot bind because gateway has no listeners")
|
|
||||||
}
|
|
||||||
|
|
||||||
didBind := false
|
|
||||||
for i, listener := range e.Listeners {
|
|
||||||
if listener.Name == ref.SectionName || ref.SectionName == "" {
|
|
||||||
if listener.BindRoute(route) {
|
|
||||||
didBind = true
|
|
||||||
e.Listeners[i] = listener
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !didBind {
|
|
||||||
return false, fmt.Errorf("invalid section name: %s", ref.SectionName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *BoundAPIGatewayConfigEntry) UnbindRoute(route BoundRoute) bool {
|
|
||||||
didUnbind := false
|
|
||||||
for i, listener := range e.Listeners {
|
|
||||||
if listener.UnbindRoute(route) {
|
|
||||||
didUnbind = true
|
|
||||||
e.Listeners[i] = listener
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return didUnbind
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoundAPIGatewayListener is an API gateway listener with information
|
// BoundAPIGatewayListener is an API gateway listener with information
|
||||||
// about the routes and certificates that have successfully bound to it.
|
// about the routes and certificates that have successfully bound to it.
|
||||||
type BoundAPIGatewayListener struct {
|
type BoundAPIGatewayListener struct {
|
||||||
|
@ -1061,13 +990,14 @@ type BoundAPIGatewayListener struct {
|
||||||
|
|
||||||
// BindRoute is used to create or update a route on the listener.
|
// BindRoute is used to create or update a route on the listener.
|
||||||
// It returns true if the route was able to be bound to the listener.
|
// It returns true if the route was able to be bound to the listener.
|
||||||
|
// Routes should only bind to listeners with their same section name
|
||||||
|
// and protocol. Be sure to check both of these before attempting
|
||||||
|
// to bind a route to the listener.
|
||||||
func (l *BoundAPIGatewayListener) BindRoute(route BoundRoute) bool {
|
func (l *BoundAPIGatewayListener) BindRoute(route BoundRoute) bool {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (t-eckert): Add a check that the listener has the same `protocol` as the route. Fail to bind if the protocols do not match.
|
|
||||||
|
|
||||||
// Convert the abstract route interface to a ResourceReference.
|
// Convert the abstract route interface to a ResourceReference.
|
||||||
routeRef := ResourceReference{
|
routeRef := ResourceReference{
|
||||||
Kind: route.GetKind(),
|
Kind: route.GetKind(),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -1343,289 +1342,6 @@ func TestBoundAPIGateway(t *testing.T) {
|
||||||
testConfigEntryNormalizeAndValidate(t, cases)
|
testConfigEntryNormalizeAndValidate(t, cases)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBoundAPIGatewayBindRoute(t *testing.T) {
|
|
||||||
cases := map[string]struct {
|
|
||||||
gateway BoundAPIGatewayConfigEntry
|
|
||||||
route BoundRoute
|
|
||||||
expectedGateway BoundAPIGatewayConfigEntry
|
|
||||||
expectedDidBind bool
|
|
||||||
expectedErr error
|
|
||||||
}{
|
|
||||||
"Bind TCP Route to Gateway": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{
|
|
||||||
{
|
|
||||||
Name: "Test Listener",
|
|
||||||
Routes: []ResourceReference{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: APIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
SectionName: "Test Listener",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{
|
|
||||||
{
|
|
||||||
Name: "Test Listener",
|
|
||||||
Routes: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedDidBind: true,
|
|
||||||
},
|
|
||||||
"Bind TCP Route with wildcard section name to all listeners on Gateway": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{
|
|
||||||
{
|
|
||||||
Name: "Test Listener 1",
|
|
||||||
Routes: []ResourceReference{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Test Listener 2",
|
|
||||||
Routes: []ResourceReference{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Test Listener 3",
|
|
||||||
Routes: []ResourceReference{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: APIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{
|
|
||||||
{
|
|
||||||
Name: "Test Listener 1",
|
|
||||||
Routes: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Test Listener 2",
|
|
||||||
Routes: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Test Listener 3",
|
|
||||||
Routes: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedDidBind: true,
|
|
||||||
},
|
|
||||||
"TCP Route cannot bind to Gateway because the parent reference kind is not APIGateway": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
SectionName: "Test Listener",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: TerminatingGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
expectedDidBind: false,
|
|
||||||
expectedErr: nil,
|
|
||||||
},
|
|
||||||
"TCP Route cannot bind to Gateway because the parent reference name does not match": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: APIGateway,
|
|
||||||
Name: "Other Test Bound API Gateway",
|
|
||||||
SectionName: "Test Listener",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
expectedDidBind: false,
|
|
||||||
expectedErr: nil,
|
|
||||||
},
|
|
||||||
"TCP Route cannot bind to Gateway because it lacks listeners": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: APIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
SectionName: "Test Listener",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
expectedDidBind: false,
|
|
||||||
expectedErr: fmt.Errorf("route cannot bind because gateway has no listeners"),
|
|
||||||
},
|
|
||||||
"TCP Route cannot bind to Gateway because it has an invalid section name": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: APIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
SectionName: "Other Test Listener",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{},
|
|
||||||
},
|
|
||||||
expectedDidBind: false,
|
|
||||||
expectedErr: fmt.Errorf("route cannot bind because gateway has no listeners"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range cases {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
ref := tc.route.GetParents()[0]
|
|
||||||
|
|
||||||
actualDidBind, actualErr := tc.gateway.BindRoute(ref, tc.route)
|
|
||||||
|
|
||||||
require.Equal(t, tc.expectedDidBind, actualDidBind)
|
|
||||||
require.Equal(t, tc.expectedErr, actualErr)
|
|
||||||
require.Equal(t, tc.expectedGateway.Listeners, tc.gateway.Listeners)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBoundAPIGatewayUnbindRoute(t *testing.T) {
|
|
||||||
cases := map[string]struct {
|
|
||||||
gateway BoundAPIGatewayConfigEntry
|
|
||||||
route BoundRoute
|
|
||||||
expectedGateway BoundAPIGatewayConfigEntry
|
|
||||||
expectedDidUnbind bool
|
|
||||||
}{
|
|
||||||
"TCP Route unbinds from Gateway": {
|
|
||||||
gateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{
|
|
||||||
{
|
|
||||||
Name: "Test Listener",
|
|
||||||
Routes: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
route: &TCPRouteConfigEntry{
|
|
||||||
Kind: TCPRoute,
|
|
||||||
Name: "Test Route",
|
|
||||||
Parents: []ResourceReference{
|
|
||||||
{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Other Test Bound API Gateway",
|
|
||||||
SectionName: "Test Listener",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedGateway: BoundAPIGatewayConfigEntry{
|
|
||||||
Kind: BoundAPIGateway,
|
|
||||||
Name: "Test Bound API Gateway",
|
|
||||||
Listeners: []BoundAPIGatewayListener{
|
|
||||||
{
|
|
||||||
Name: "Test Listener",
|
|
||||||
Routes: []ResourceReference{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedDidUnbind: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range cases {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
actualDidUnbind := tc.gateway.UnbindRoute(tc.route)
|
|
||||||
|
|
||||||
require.Equal(t, tc.expectedDidUnbind, actualDidUnbind)
|
|
||||||
require.Equal(t, tc.expectedGateway.Listeners, tc.gateway.Listeners)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListenerBindRoute(t *testing.T) {
|
func TestListenerBindRoute(t *testing.T) {
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
listener BoundAPIGatewayListener
|
listener BoundAPIGatewayListener
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
type BoundRoute interface {
|
type BoundRoute interface {
|
||||||
ConfigEntry
|
ConfigEntry
|
||||||
GetParents() []ResourceReference
|
GetParents() []ResourceReference
|
||||||
|
GetProtocol() APIGatewayListenerProtocol
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPRouteConfigEntry manages the configuration for a HTTP route
|
// HTTPRouteConfigEntry manages the configuration for a HTTP route
|
||||||
|
@ -39,6 +40,18 @@ func (e *HTTPRouteConfigEntry) GetName() string {
|
||||||
return e.Name
|
return e.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *HTTPRouteConfigEntry) GetParents() []ResourceReference {
|
||||||
|
if e == nil {
|
||||||
|
return []ResourceReference{}
|
||||||
|
}
|
||||||
|
// TODO HTTP Route should have "parents". Andrew will implement this in his work.
|
||||||
|
return []ResourceReference{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HTTPRouteConfigEntry) GetProtocol() APIGatewayListenerProtocol {
|
||||||
|
return ListenerProtocolHTTP
|
||||||
|
}
|
||||||
|
|
||||||
func (e *HTTPRouteConfigEntry) Normalize() error {
|
func (e *HTTPRouteConfigEntry) Normalize() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -115,6 +128,17 @@ func (e *TCPRouteConfigEntry) GetName() string {
|
||||||
return e.Name
|
return e.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *TCPRouteConfigEntry) GetParents() []ResourceReference {
|
||||||
|
if e == nil {
|
||||||
|
return []ResourceReference{}
|
||||||
|
}
|
||||||
|
return e.Parents
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TCPRouteConfigEntry) GetProtocol() APIGatewayListenerProtocol {
|
||||||
|
return ListenerProtocolTCP
|
||||||
|
}
|
||||||
|
|
||||||
func (e *TCPRouteConfigEntry) GetMeta() map[string]string {
|
func (e *TCPRouteConfigEntry) GetMeta() map[string]string {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -160,13 +184,6 @@ func (e *TCPRouteConfigEntry) CanWrite(authz acl.Authorizer) error {
|
||||||
return authz.ToAllowAuthorizer().MeshWriteAllowed(&authzContext)
|
return authz.ToAllowAuthorizer().MeshWriteAllowed(&authzContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *TCPRouteConfigEntry) GetParents() []ResourceReference {
|
|
||||||
if e == nil {
|
|
||||||
return []ResourceReference{}
|
|
||||||
}
|
|
||||||
return e.Parents
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *TCPRouteConfigEntry) GetRaftIndex() *RaftIndex {
|
func (e *TCPRouteConfigEntry) GetRaftIndex() *RaftIndex {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return &RaftIndex{}
|
return &RaftIndex{}
|
||||||
|
|
Loading…
Reference in New Issue