-
Notifications
You must be signed in to change notification settings - Fork 593
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
combine services across different httproutes
- Loading branch information
1 parent
792ce60
commit 01ab6bc
Showing
9 changed files
with
1,708 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
internal/dataplane/translator/subtranslator/backendref.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package subtranslator | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/go-logr/logr" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/kongstate" | ||
"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi" | ||
"github.com/kong/kubernetes-ingress-controller/v3/internal/store" | ||
"github.com/kong/kubernetes-ingress-controller/v3/internal/util" | ||
) | ||
|
||
// backendRefsToKongStateBackends takes a list of BackendRefs and returns a list of ServiceBackends. | ||
// The backendRefs are checked for the following conditions. If any of these conditions are met, the BackendRef is | ||
// not included in the returned list: | ||
// - If a BackendRef is not permitted by the provided ReferenceGrantTo set, | ||
// - If a BackendRef is not found, | ||
// - If a BackendRef Group & Kind pair is not supported (currently only Service is supported), | ||
// - If a BackendRef is missing a port. | ||
// The provided client is used to retrieve the Backend referenced by the BackendRef | ||
// to check if it exists. | ||
func backendRefsToKongStateBackends( | ||
logger logr.Logger, | ||
storer store.Storer, | ||
routes []client.Object, | ||
backendRefs []gatewayapi.BackendRef, | ||
aggregatedAllowedMap map[gatewayapi.ReferenceGrantFrom]map[gatewayapi.Namespace][]gatewayapi.ReferenceGrantTo, | ||
) kongstate.ServiceBackends { | ||
backends := kongstate.ServiceBackends{} | ||
|
||
for _, backendRef := range backendRefs { | ||
logger := loggerForBackendRef(logger, routes[0], backendRef) | ||
|
||
nn := client.ObjectKey{ | ||
Name: string(backendRef.Name), | ||
Namespace: routes[0].GetNamespace(), | ||
} | ||
if backendRef.Namespace != nil { | ||
nn.Namespace = string(*backendRef.Namespace) | ||
} | ||
|
||
if backendRef.Kind == nil { | ||
// This should never happen as the default value defined by Gateway API is 'Service'. Checking just in case. | ||
logger.Error(nil, "Object requested backendRef to target, but no Kind was specified, skipping...") | ||
continue | ||
} | ||
|
||
var err error | ||
switch *backendRef.Kind { | ||
case "Service": | ||
_, err = storer.GetService(nn.Namespace, nn.Name) | ||
default: | ||
err = fmt.Errorf("unsupported kind %q, only 'Service' is supported", *backendRef.Kind) | ||
} | ||
if err != nil { | ||
if errors.As(err, &store.NotFoundError{}) { | ||
logger.Error(err, "Object requested backendRef to target, but it does not exist, skipping...") | ||
} else { | ||
logger.Error(err, "Object requested backendRef to target, but an error occurred, skipping...") | ||
} | ||
continue | ||
} | ||
|
||
if err := backendRefAllowedForRoutes(logger, routes, backendRef, aggregatedAllowedMap); err != nil { | ||
// we log impermissible refs rather than failing the entire rule. while we cannot actually route to | ||
// these, we do not want a single impermissible ref to take the entire rule offline. in the case of edits, | ||
// failing the entire rule could potentially delete routes that were previously online and in use, and | ||
// that remain viable (because they still have some permissible backendRefs) | ||
logger.Error(err, "Object requested backendRef to target, but no ReferenceGrant permits it, skipping...") | ||
continue | ||
} | ||
|
||
port := int32(-1) | ||
if backendRef.Port != nil { | ||
port = int32(*backendRef.Port) | ||
} | ||
backend, err := kongstate.NewServiceBackendForService( | ||
nn, | ||
kongstate.PortDef{ | ||
Mode: kongstate.PortModeByNumber, | ||
Number: port, | ||
}, | ||
) | ||
if err != nil { | ||
logger.Error(err, "failed to create ServiceBackend for backendRef") | ||
continue | ||
} | ||
if backendRef.Weight != nil { | ||
backend.SetWeight(*backendRef.Weight) | ||
} | ||
backends = append(backends, backend) | ||
} | ||
|
||
return backends | ||
} | ||
|
||
func backendRefAllowedForRoutes( | ||
logger logr.Logger, | ||
routes []client.Object, | ||
backendRef gatewayapi.BackendRef, | ||
aggregatewAllowedMap map[gatewayapi.ReferenceGrantFrom]map[gatewayapi.Namespace][]gatewayapi.ReferenceGrantTo, | ||
) error { | ||
if !util.IsBackendRefGroupKindSupported(backendRef.Group, backendRef.Kind) { | ||
group := "core" | ||
if backendRef.Group != nil || *backendRef.Group == "" { | ||
group = string(*backendRef.Group) | ||
} | ||
return fmt.Errorf("backendRef kind does is not supported: %s/%s", group, *backendRef.Kind) | ||
} | ||
for _, route := range routes { | ||
grantFrom := gatewayapi.ReferenceGrantFrom{ | ||
Group: gatewayapi.Group(route.GetObjectKind().GroupVersionKind().Group), | ||
Kind: gatewayapi.Kind(route.GetObjectKind().GroupVersionKind().Kind), | ||
Namespace: gatewayapi.Namespace(route.GetNamespace()), | ||
} | ||
allowed, ok := aggregatewAllowedMap[grantFrom] | ||
if !ok || | ||
!gatewayapi.NewRefCheckerForRoute(logger, route, backendRef). | ||
IsRefAllowedByGrant(allowed) { | ||
return fmt.Errorf("No ReferenceGrant found from %s/%s %s/%s to the backend", | ||
route.GetObjectKind().GroupVersionKind().Group, | ||
route.GetObjectKind().GroupVersionKind().Kind, | ||
route.GetNamespace(), | ||
route.GetName(), | ||
) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func loggerForBackendRef(logger logr.Logger, route client.Object, backendRef gatewayapi.BackendRef) logr.Logger { | ||
var ( | ||
namespace = route.GetNamespace() | ||
kind = "unknown" | ||
) | ||
if backendRef.Namespace != nil { | ||
namespace = string(*backendRef.Namespace) | ||
} | ||
if backendRef.Kind != nil { | ||
kind = string(*backendRef.Kind) | ||
} | ||
|
||
objName := fmt.Sprintf("%s %s/%s", | ||
route.GetObjectKind().GroupVersionKind().String(), | ||
route.GetNamespace(), | ||
route.GetName()) | ||
return logger.WithValues( | ||
"object_name", objName, | ||
"target_kind", kind, | ||
"target_namespace", namespace, | ||
"target_name", backendRef.Name, | ||
) | ||
} |
Oops, something went wrong.