From ed7317c7205da34801a3f7cf89f9c62a873bdf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Mon, 5 Sep 2022 15:05:41 +0200 Subject: [PATCH] chore: replace gatewayv1alpha2.HTTPRoute with gatewayv1beta1.HTTPRoute --- .golangci.yaml | 1 + CHANGELOG.md | 1 + internal/admission/server.go | 3 +- internal/admission/server_test.go | 3 +- internal/admission/validator.go | 4 +- .../controllers/gateway/gateway_controller.go | 6 +- .../gateway/gateway_controller_test.go | 4 +- internal/controllers/gateway/gateway_utils.go | 4 +- .../gateway/gatewayclass_controller.go | 5 +- .../gateway/httproute_controller.go | 58 ++-- internal/controllers/gateway/route_utils.go | 116 ++++--- .../controllers/gateway/route_utils_test.go | 103 +++--- .../gateway/tcproute_controller.go | 4 +- .../gateway/tlsroute_controller.go | 4 +- .../gateway/udproute_controller.go | 4 +- internal/dataplane/kongstate/util_test.go | 3 +- internal/dataplane/parser/parser.go | 3 +- .../dataplane/parser/translate_httproute.go | 28 +- .../parser/translate_httproute_test.go | 294 +++++++++--------- .../dataplane/parser/translate_tcproute.go | 2 +- .../dataplane/parser/translate_tlsroute.go | 2 +- .../dataplane/parser/translate_udproute.go | 2 +- internal/dataplane/parser/translate_utils.go | 93 ++---- .../dataplane/parser/translate_utils_test.go | 158 +++++----- .../dataplane/parser/wrappers_backendref.go | 144 +++++++++ .../dataplane/parser/wrappers_refchecker.go | 100 ++++++ internal/store/fake_store.go | 3 +- internal/store/fake_store_test.go | 7 +- internal/store/store.go | 17 +- internal/types/types.go | 32 ++ internal/util/conversions.go | 16 + internal/util/hostname.go | 14 +- internal/util/k8s.go | 4 +- internal/validation/gateway/httproute.go | 18 +- internal/validation/gateway/httproute_test.go | 171 +++++----- test/conformance/gateway_conformance_test.go | 2 +- test/e2e/helpers_gateway_test.go | 34 +- test/integration/gateway_test.go | 40 +-- test/integration/helpers_test.go | 69 ++-- test/integration/httproute_test.go | 77 ++--- test/integration/httproute_webhook_test.go | 48 +-- 41 files changed, 1025 insertions(+), 676 deletions(-) create mode 100644 internal/dataplane/parser/wrappers_backendref.go create mode 100644 internal/dataplane/parser/wrappers_refchecker.go create mode 100644 internal/types/types.go diff --git a/.golangci.yaml b/.golangci.yaml index 256bbc0187..4e0c30af2d 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -70,6 +70,7 @@ linters-settings: alias: gateway${1} issues: fix: true + max-same-issues: 0 exclude-rules: - linters: - ineffassign diff --git a/CHANGELOG.md b/CHANGELOG.md index 55b5d96cdb..9c4d4503ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ - Added support for Gateway API's v1beta1 versions of: GatewayClass, Gateway and HTTPRoute. [#2889](https://github.com/Kong/kubernetes-ingress-controller/issues/2889) + [#2894](https://github.com/Kong/kubernetes-ingress-controller/issues/2894) #### Fixed diff --git a/internal/admission/server.go b/internal/admission/server.go index e44c9008f9..77200057b7 100644 --- a/internal/admission/server.go +++ b/internal/admission/server.go @@ -17,6 +17,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" "sigs.k8s.io/controller-runtime/pkg/certwatcher" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" configuration "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" ) @@ -304,7 +305,7 @@ func (a RequestHandler) handleValidation(ctx context.Context, request admissionv return nil, err } case httprouteGVResource: - httproute := gatewayv1alpha2.HTTPRoute{} + httproute := gatewayv1beta1.HTTPRoute{} deserializer := codecs.UniversalDeserializer() _, _, err = deserializer.Decode(request.Object.Raw, nil, &httproute) if err != nil { diff --git a/internal/admission/server_test.go b/internal/admission/server_test.go index eba271cdcf..344f02df65 100644 --- a/internal/admission/server_test.go +++ b/internal/admission/server_test.go @@ -16,6 +16,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" configuration "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" ) @@ -54,7 +55,7 @@ func (v KongFakeValidator) ValidateGateway(ctx context.Context, gateway gatewayv return v.Result, v.Message, v.Error } -func (v KongFakeValidator) ValidateHTTPRoute(ctx context.Context, gateway gatewayv1alpha2.HTTPRoute) (bool, string, error) { +func (v KongFakeValidator) ValidateHTTPRoute(ctx context.Context, gateway gatewayv1beta1.HTTPRoute) (bool, string, error) { return v.Result, v.Message, v.Error } diff --git a/internal/admission/validator.go b/internal/admission/validator.go index 7a34203b9b..394f3cf3b1 100644 --- a/internal/admission/validator.go +++ b/internal/admission/validator.go @@ -29,7 +29,7 @@ type KongValidator interface { ValidateClusterPlugin(ctx context.Context, plugin kongv1.KongClusterPlugin) (bool, string, error) ValidateCredential(ctx context.Context, secret corev1.Secret) (bool, string, error) ValidateGateway(ctx context.Context, gateway gatewayv1alpha2.Gateway) (bool, string, error) - ValidateHTTPRoute(ctx context.Context, httproute gatewayv1alpha2.HTTPRoute) (bool, string, error) + ValidateHTTPRoute(ctx context.Context, httproute gatewayv1beta1.HTTPRoute) (bool, string, error) } // KongHTTPValidator implements KongValidator interface to validate Kong @@ -324,7 +324,7 @@ func (validator KongHTTPValidator) ValidateGateway( } func (validator KongHTTPValidator) ValidateHTTPRoute( - ctx context.Context, httproute gatewayv1alpha2.HTTPRoute, + ctx context.Context, httproute gatewayv1beta1.HTTPRoute, ) (bool, string, error) { // in order to be sure whether or not an HTTPRoute resource is managed by this // controller we disallow references to Gateway resources that do not exist. diff --git a/internal/controllers/gateway/gateway_controller.go b/internal/controllers/gateway/gateway_controller.go index 7b60f3d5ef..e06c3aba24 100644 --- a/internal/controllers/gateway/gateway_controller.go +++ b/internal/controllers/gateway/gateway_controller.go @@ -147,7 +147,7 @@ func (r *GatewayReconciler) gatewayHasMatchingGatewayClass(obj client.Object) bo r.Log.Error(err, "could not retrieve gatewayclass", "gatewayclass", gateway.Spec.GatewayClassName) return false } - return gatewayClass.Spec.ControllerName == gatewayv1beta1.GatewayController(ControllerName) + return gatewayClass.Spec.ControllerName == ControllerName } // gatewayClassMatchesController is a watch predicate which filters out events for gatewayclasses which @@ -158,7 +158,7 @@ func (r *GatewayReconciler) gatewayClassMatchesController(obj client.Object) boo r.Log.Error(fmt.Errorf("unexpected object type in gatewayclass watch predicates"), "expected", "*gatewayv1beta1.GatewayClass", "found", reflect.TypeOf(obj)) return false } - return gatewayClass.Spec.ControllerName == gatewayv1beta1.GatewayController(ControllerName) + return gatewayClass.Spec.ControllerName == ControllerName } // listGatewaysForGatewayClass is a watch predicate which finds all the gateway objects reference @@ -291,7 +291,7 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct debug(log, gateway, "ensured object was removed from the data-plane (if ever present)") return ctrl.Result{}, r.DataplaneClient.DeleteObject(gateway) } - if gwc.Spec.ControllerName != gatewayv1beta1.GatewayController(ControllerName) { + if gwc.Spec.ControllerName != ControllerName { debug(log, gateway, "unsupported gatewayclass controllername, ignoring", "gatewayclass", gwc.Name, "controllername", gwc.Spec.ControllerName) if err := r.DataplaneClient.DeleteObject(gateway); err != nil { debug(log, gateway, "failed to delete object from data-plane, requeuing") diff --git a/internal/controllers/gateway/gateway_controller_test.go b/internal/controllers/gateway/gateway_controller_test.go index 4a1da50ac9..bd59de1447 100644 --- a/internal/controllers/gateway/gateway_controller_test.go +++ b/internal/controllers/gateway/gateway_controller_test.go @@ -236,7 +236,7 @@ func Test_reconcileGatewaysIfClassMatches(t *testing.T) { Name: "us", }, Spec: gatewayv1beta1.GatewayClassSpec{ - ControllerName: gatewayv1beta1.GatewayController(ControllerName), + ControllerName: ControllerName, }, } @@ -331,7 +331,7 @@ func Test_isGatewayControlledAndUnmanagedMode(t *testing.T) { Name: "us", }, Spec: gatewayv1beta1.GatewayClassSpec{ - ControllerName: gatewayv1beta1.GatewayController(ControllerName), + ControllerName: ControllerName, }, } diff --git a/internal/controllers/gateway/gateway_utils.go b/internal/controllers/gateway/gateway_utils.go index a77e51da4d..9cedc76b0e 100644 --- a/internal/controllers/gateway/gateway_utils.go +++ b/internal/controllers/gateway/gateway_utils.go @@ -70,7 +70,7 @@ func isGatewayReady(gateway *gatewayv1alpha2.Gateway) bool { // is controlled by this controller and the gateway is configured for unmanaged mode. func isGatewayInClassAndUnmanaged(gatewayClass *gatewayv1beta1.GatewayClass, gateway gatewayv1alpha2.Gateway) bool { _, ok := annotations.ExtractUnmanagedGatewayMode(gateway.Annotations) - return ok && gatewayClass.Spec.ControllerName == gatewayv1beta1.GatewayController(ControllerName) + return ok && gatewayClass.Spec.ControllerName == ControllerName } // getRefFromPublishService splits a publish service string in the format namespace/name into a types.NamespacedName @@ -553,7 +553,7 @@ func isGatewayClassEventInClass(log logr.Logger, watchEvent interface{}) bool { log.Error(fmt.Errorf("invalid type"), "received invalid object type in event handlers", "expected", "GatewayClass", "found", reflect.TypeOf(obj)) continue } - if gwc.Spec.ControllerName == gatewayv1beta1.GatewayController(ControllerName) { + if gwc.Spec.ControllerName == ControllerName { return true } } diff --git a/internal/controllers/gateway/gatewayclass_controller.go b/internal/controllers/gateway/gatewayclass_controller.go index 499de94929..e1ea622d6e 100644 --- a/internal/controllers/gateway/gatewayclass_controller.go +++ b/internal/controllers/gateway/gatewayclass_controller.go @@ -13,7 +13,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" @@ -27,7 +26,7 @@ const ( // ControllerName is the unique identifier for this controller and is used // within GatewayClass resources to indicate that this controller should // support connected Gateway resources. - ControllerName gatewayv1alpha2.GatewayController = "konghq.com/kic-gateway-controller" + ControllerName gatewayv1beta1.GatewayController = "konghq.com/kic-gateway-controller" ) // ----------------------------------------------------------------------------- @@ -80,7 +79,7 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request } log.V(util.DebugLevel).Info("processing gatewayclass", "name", req.Name) - if gwc.Spec.ControllerName == gatewayv1beta1.GatewayController(ControllerName) { + if gwc.Spec.ControllerName == ControllerName { alreadyAccepted := false for _, cond := range gwc.Status.Conditions { if cond.Reason == string(gatewayv1beta1.GatewayClassConditionStatusAccepted) { diff --git a/internal/controllers/gateway/httproute_controller.go b/internal/controllers/gateway/httproute_controller.go index cee85a95fb..db16b97619 100644 --- a/internal/controllers/gateway/httproute_controller.go +++ b/internal/controllers/gateway/httproute_controller.go @@ -90,7 +90,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { // data-plane config for an HTTPRoute if it somehow becomes disconnected from // a supported Gateway and GatewayClass. return c.Watch( - &source.Kind{Type: &gatewayv1alpha2.HTTPRoute{}}, + &source.Kind{Type: &gatewayv1beta1.HTTPRoute{}}, &handler.EnqueueRequestForObject{}, ) } @@ -138,7 +138,7 @@ func (r *HTTPRouteReconciler) listHTTPRoutesForGatewayClass(obj client.Object) [ } // map all HTTPRoute objects - httprouteList := gatewayv1alpha2.HTTPRouteList{} + httprouteList := gatewayv1beta1.HTTPRouteList{} if err := r.Client.List(context.Background(), &httprouteList); err != nil { r.Log.Error(err, "failed to list httproute objects from the cached client") return nil @@ -199,7 +199,7 @@ func (r *HTTPRouteReconciler) listHTTPRoutesForGateway(obj client.Object) []reco } // map all HTTPRoute objects - httprouteList := gatewayv1alpha2.HTTPRouteList{} + httprouteList := gatewayv1beta1.HTTPRouteList{} if err := r.Client.List(context.Background(), &httprouteList); err != nil { r.Log.Error(err, "failed to list httproute objects from the cached client") return nil @@ -239,7 +239,7 @@ func (r *HTTPRouteReconciler) listHTTPRoutesForGateway(obj client.Object) []reco func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := r.Log.WithValues("NetV1Alpha2HTTPRoute", req.NamespacedName) - httproute := new(gatewayv1alpha2.HTTPRoute) + httproute := new(gatewayv1beta1.HTTPRoute) if err := r.Get(ctx, req.NamespacedName, httproute); err != nil { // if the queued object is no longer present in the proxy cache we need // to ensure that if it was ever added to the cache, it gets removed. @@ -366,9 +366,9 @@ var httprouteParentKind = "Gateway" // ensureGatewayReferenceStatus takes any number of Gateways that should be // considered "attached" to a given HTTPRoute and ensures that the status // for the HTTPRoute is updated appropriately. -func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Context, httproute *gatewayv1alpha2.HTTPRoute, gateways ...supportedGatewayWithCondition) (bool, error) { +func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Context, httproute *gatewayv1beta1.HTTPRoute, gateways ...supportedGatewayWithCondition) (bool, error) { // map the existing parentStatues to avoid duplications - parentStatuses := make(map[string]*gatewayv1alpha2.RouteParentStatus) + parentStatuses := make(map[string]*gatewayv1beta1.RouteParentStatus) for _, existingParent := range httproute.Status.Parents { namespace := httproute.Namespace if existingParent.ParentRef.Namespace != nil { @@ -386,12 +386,12 @@ func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Cont statusChangesWereMade := false for _, gateway := range gateways { // build a new status for the parent Gateway - gatewayParentStatus := &gatewayv1alpha2.RouteParentStatus{ - ParentRef: gatewayv1alpha2.ParentReference{ - Group: (*gatewayv1alpha2.Group)(&gatewayv1alpha2.GroupVersion.Group), - Kind: util.StringToGatewayAPIKindPtr(httprouteParentKind), - Namespace: (*gatewayv1alpha2.Namespace)(&gateway.gateway.Namespace), - Name: gatewayv1alpha2.ObjectName(gateway.gateway.Name), + gatewayParentStatus := &gatewayv1beta1.RouteParentStatus{ + ParentRef: gatewayv1beta1.ParentReference{ + Group: (*gatewayv1beta1.Group)(&gatewayv1beta1.GroupVersion.Group), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr(httprouteParentKind), + Namespace: (*gatewayv1beta1.Namespace)(&gateway.gateway.Namespace), + Name: gatewayv1beta1.ObjectName(gateway.gateway.Name), }, ControllerName: ControllerName, Conditions: []metav1.Condition{{ @@ -403,7 +403,7 @@ func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Cont }}, } if gateway.listenerName != "" { - gatewayParentStatus.ParentRef.SectionName = (*gatewayv1alpha2.SectionName)(pointer.StringPtr(gateway.listenerName)) + gatewayParentStatus.ParentRef.SectionName = (*gatewayv1beta1.SectionName)(pointer.StringPtr(gateway.listenerName)) } key := fmt.Sprintf("%s/%s/%s", gateway.gateway.Namespace, gateway.gateway.Name, gateway.listenerName) @@ -438,7 +438,7 @@ func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Cont } // update the httproute status with the new status references - httproute.Status.Parents = make([]gatewayv1alpha2.RouteParentStatus, 0, len(parentStatuses)) + httproute.Status.Parents = make([]gatewayv1beta1.RouteParentStatus, 0, len(parentStatuses)) for _, parent := range parentStatuses { httproute.Status.Parents = append(httproute.Status.Parents, *parent) } @@ -455,9 +455,9 @@ func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Cont // ensureGatewayReferenceStatusRemoved uses the ControllerName provided by the Gateway // implementation to prune status references to Gateways supported by this controller // in the provided HTTPRoute object. -func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusRemoved(ctx context.Context, httproute *gatewayv1alpha2.HTTPRoute) (bool, error) { +func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusRemoved(ctx context.Context, httproute *gatewayv1beta1.HTTPRoute) (bool, error) { // drop all status references to supported Gateway objects - newStatuses := make([]gatewayv1alpha2.RouteParentStatus, 0) + newStatuses := make([]gatewayv1beta1.RouteParentStatus, 0) for _, status := range httproute.Status.Parents { if status.ControllerName != ControllerName { newStatuses = append(newStatuses, status) @@ -481,14 +481,18 @@ func (r *HTTPRouteReconciler) ensureGatewayReferenceStatusRemoved(ctx context.Co } // setRouteConditionResolvedRefsCondition sets a condition of type ResolvedRefs on the route status. -func (r *HTTPRouteReconciler) setRouteConditionResolvedRefsCondition(ctx context.Context, httpRoute *gatewayv1alpha2.HTTPRoute, parentStatuses map[string]*gatewayv1alpha2.RouteParentStatus) (map[string]*gatewayv1alpha2.RouteParentStatus, bool, error) { +func (r *HTTPRouteReconciler) setRouteConditionResolvedRefsCondition( + ctx context.Context, + httpRoute *gatewayv1beta1.HTTPRoute, + parentStatuses map[string]*gatewayv1beta1.RouteParentStatus, +) (map[string]*gatewayv1beta1.RouteParentStatus, bool, error) { var changed bool resolvedRefsStatus := metav1.ConditionFalse reason, err := r.getHTTPRouteRuleReason(ctx, *httpRoute) if err != nil { return nil, false, err } - if reason == gatewayv1alpha2.RouteReasonResolvedRefs { + if reason == gatewayv1beta1.RouteReasonResolvedRefs { resolvedRefsStatus = metav1.ConditionTrue } @@ -497,7 +501,7 @@ func (r *HTTPRouteReconciler) setRouteConditionResolvedRefsCondition(ctx context for _, parentStatus := range parentStatuses { var conditionFound bool for _, cond := range parentStatus.Conditions { - if cond.Type == string(gatewayv1alpha2.RouteConditionResolvedRefs) && + if cond.Type == string(gatewayv1beta1.RouteConditionResolvedRefs) && cond.Status == resolvedRefsStatus && cond.Reason == string(reason) { conditionFound = true @@ -506,7 +510,7 @@ func (r *HTTPRouteReconciler) setRouteConditionResolvedRefsCondition(ctx context } if !conditionFound { parentStatus.Conditions = append(parentStatus.Conditions, metav1.Condition{ - Type: string(gatewayv1alpha2.RouteConditionResolvedRefs), + Type: string(gatewayv1beta1.RouteConditionResolvedRefs), Status: resolvedRefsStatus, ObservedGeneration: httpRoute.Generation, LastTransitionTime: metav1.Now(), @@ -519,7 +523,7 @@ func (r *HTTPRouteReconciler) setRouteConditionResolvedRefsCondition(ctx context return parentStatuses, changed, nil } -func (r *HTTPRouteReconciler) getHTTPRouteRuleReason(ctx context.Context, httpRoute gatewayv1alpha2.HTTPRoute) (gatewayv1alpha2.RouteConditionReason, error) { +func (r *HTTPRouteReconciler) getHTTPRouteRuleReason(ctx context.Context, httpRoute gatewayv1beta1.HTTPRoute) (gatewayv1beta1.RouteConditionReason, error) { for _, rule := range httpRoute.Spec.Rules { for _, backendRef := range rule.BackendRefs { backendNamespace := httpRoute.Namespace @@ -529,7 +533,7 @@ func (r *HTTPRouteReconciler) getHTTPRouteRuleReason(ctx context.Context, httpRo // Check if the BackendRef GroupKind is supported if !util.IsBackendRefGroupKindSupported(backendRef.Group, backendRef.Kind) { - return gatewayv1alpha2.RouteReasonInvalidKind, nil + return gatewayv1beta1.RouteReasonInvalidKind, nil } // Check if all the objects referenced actually exist @@ -540,14 +544,14 @@ func (r *HTTPRouteReconciler) getHTTPRouteRuleReason(ctx context.Context, httpRo if !k8serrors.IsNotFound(err) { return "", err } - return gatewayv1alpha2.RouteReasonBackendNotFound, nil + return gatewayv1beta1.RouteReasonBackendNotFound, nil } // Check if the object referenced is in another namespace, // and if there is grant for that reference if httpRoute.Namespace != backendNamespace { if !r.EnableReferenceGrant { - return gatewayv1alpha2.RouteReasonRefNotPermitted, nil + return gatewayv1beta1.RouteReasonRefNotPermitted, nil } referenceGrantList := &gatewayv1alpha2.ReferenceGrantList{} @@ -555,7 +559,7 @@ func (r *HTTPRouteReconciler) getHTTPRouteRuleReason(ctx context.Context, httpRo return "", err } if len(referenceGrantList.Items) == 0 { - return gatewayv1alpha2.RouteReasonRefNotPermitted, nil + return gatewayv1beta1.RouteReasonRefNotPermitted, nil } var isGranted bool for _, grant := range referenceGrantList.Items { @@ -565,10 +569,10 @@ func (r *HTTPRouteReconciler) getHTTPRouteRuleReason(ctx context.Context, httpRo } } if !isGranted { - return gatewayv1alpha2.RouteReasonRefNotPermitted, nil + return gatewayv1beta1.RouteReasonRefNotPermitted, nil } } } } - return gatewayv1alpha2.RouteReasonResolvedRefs, nil + return gatewayv1beta1.RouteReasonResolvedRefs, nil } diff --git a/internal/controllers/gateway/route_utils.go b/internal/controllers/gateway/route_utils.go index ff1372d862..037cd7e0ee 100644 --- a/internal/controllers/gateway/route_utils.go +++ b/internal/controllers/gateway/route_utils.go @@ -12,6 +12,7 @@ import ( gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" + "github.com/kong/kubernetes-ingress-controller/v2/internal/types" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" ) @@ -33,18 +34,38 @@ type supportedGatewayWithCondition struct { // parentRefsForRoute provides a list of the parentRefs given a Gateway APIs route object // (e.g. HTTPRoute, TCPRoute, e.t.c.) which refer to the Gateway resource(s) which manage it. -func parentRefsForRoute(obj client.Object) ([]gatewayv1alpha2.ParentReference, error) { - switch v := obj.(type) { - case *gatewayv1alpha2.HTTPRoute: - return v.Spec.ParentRefs, nil +func parentRefsForRoute[T types.RouteT](route T) ([]gatewayv1beta1.ParentReference, error) { + // Note: Ideally we wouldn't have to do this but it's hard to juggle around types + // and support gatewayv1beta1.ParentReference and gatewayv1alpha2.ParentReference + // at the same time so we just copy v1alpha2 refs to a new v1beta1 slice. + convertV1Alpha2ToV1Beta1ParentReference := func( + refsAlpha []gatewayv1alpha2.ParentReference, + ) []gatewayv1beta1.ParentReference { + ret := make([]gatewayv1beta1.ParentReference, len(refsAlpha)) + for i, v := range refsAlpha { + ret[i] = gatewayv1beta1.ParentReference{ + Group: (*gatewayv1beta1.Group)(v.Group), + Kind: (*gatewayv1beta1.Kind)(v.Kind), + Namespace: (*gatewayv1beta1.Namespace)(v.Namespace), + Name: (gatewayv1beta1.ObjectName)(v.Name), + SectionName: (*gatewayv1beta1.SectionName)(v.SectionName), + Port: (*gatewayv1beta1.PortNumber)(v.Port), + } + } + return ret + } + + switch r := (interface{})(route).(type) { + case *gatewayv1beta1.HTTPRoute: + return r.Spec.ParentRefs, nil case *gatewayv1alpha2.UDPRoute: - return v.Spec.ParentRefs, nil + return convertV1Alpha2ToV1Beta1ParentReference(r.Spec.ParentRefs), nil case *gatewayv1alpha2.TCPRoute: - return v.Spec.ParentRefs, nil + return convertV1Alpha2ToV1Beta1ParentReference(r.Spec.ParentRefs), nil case *gatewayv1alpha2.TLSRoute: - return v.Spec.ParentRefs, nil + return convertV1Alpha2ToV1Beta1ParentReference(r.Spec.ParentRefs), nil default: - return nil, fmt.Errorf("cant determine parent gateway for unsupported type %s", reflect.TypeOf(obj)) + return nil, fmt.Errorf("cant determine parent gateway for unsupported type %s", reflect.TypeOf(route)) } } @@ -52,9 +73,9 @@ func parentRefsForRoute(obj client.Object) ([]gatewayv1alpha2.ParentReference, e // Gateway APIs route object (e.g. HTTPRoute, TCPRoute, e.t.c.) from the provided cached // client if they match this controller. If there are no gateways present for this route // OR the present gateways are references to missing objects, this will return a unsupportedGW error. -func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj client.Object) ([]supportedGatewayWithCondition, error) { +func getSupportedGatewayForRoute[T types.RouteT](ctx context.Context, mgrc client.Client, route T) ([]supportedGatewayWithCondition, error) { // gather the parentrefs for this route object - parentRefs, err := parentRefsForRoute(obj) + parentRefs, err := parentRefsForRoute(route) if err != nil { return nil, err } @@ -63,7 +84,7 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl gateways := make([]supportedGatewayWithCondition, 0) for _, parentRef := range parentRefs { // gather the namespace/name for the gateway - namespace := obj.GetNamespace() + namespace := route.GetNamespace() if parentRef.Namespace != nil { // TODO: need namespace restrictions implementation done before // merging this, need to filter out objects with a disallowed NS. @@ -102,7 +123,7 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl // if the GatewayClass matches this controller we're all set and this controller // should reconcile this object. - if gatewayClass.Spec.ControllerName == gatewayv1beta1.GatewayController(ControllerName) { + if gatewayClass.Spec.ControllerName == ControllerName { allowedNamespaces := make(map[string]interface{}) // set true if we find any AllowedRoutes. there may be none, in which case any namespace is permitted filtered := false @@ -114,9 +135,9 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl // based on matching a filter for a UDP listener). This needs to be expanded to an allowedRoutes.kind // implementation with default allowed kinds when there's no user-specified filter. var oneHostnameMatch bool - switch obj := obj.(type) { - case *gatewayv1alpha2.HTTPRoute: - hostnames := obj.Spec.Hostnames + switch r := (interface{})(route).(type) { + case *gatewayv1beta1.HTTPRoute: + hostnames := r.Spec.Hostnames oneHostnameMatch = listenerHostnameIntersectWithRouteHostnames(listener, hostnames) if !(listener.Protocol == gatewayv1alpha2.HTTPProtocolType || listener.Protocol == gatewayv1alpha2.HTTPSProtocolType) { continue @@ -130,7 +151,7 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl continue } case *gatewayv1alpha2.TLSRoute: - hostnames := obj.Spec.Hostnames + hostnames := r.Spec.Hostnames oneHostnameMatch = listenerHostnameIntersectWithRouteHostnames(listener, hostnames) if listener.Protocol != gatewayv1alpha2.TLSProtocolType { continue @@ -145,7 +166,7 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl filtered = true if *listener.AllowedRoutes.Namespaces.From == gatewayv1alpha2.NamespacesFromAll { // we allow "all" by just stuffing the namespace we want to find into the map - allowedNamespaces[obj.GetNamespace()] = nil + allowedNamespaces[route.GetNamespace()] = nil } else if *listener.AllowedRoutes.Namespaces.From == gatewayv1alpha2.NamespacesFromSame { allowedNamespaces[gateway.ObjectMeta.Namespace] = nil } else if *listener.AllowedRoutes.Namespaces.From == gatewayv1alpha2.NamespacesFromSelector { @@ -168,7 +189,7 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl } } - _, allowedNamespace := allowedNamespaces[obj.GetNamespace()] + _, allowedNamespace := allowedNamespaces[route.GetNamespace()] if !filtered || allowedNamespace { // if there is no matchingHostname, the gateway Status Condition Accepted must be set to False // with reason NoMatchingListenerHostname @@ -202,25 +223,44 @@ func getSupportedGatewayForRoute(ctx context.Context, mgrc client.Client, obj cl return gateways, nil } -func listenerHostnameIntersectWithRouteHostnames(listener gatewayv1alpha2.Listener, hostnames []gatewayv1alpha2.Hostname) bool { - // if the listener has no hostname, all hostnames automatically intersect - if listener.Hostname == nil || *listener.Hostname == "" || len(hostnames) == 0 { +func listenerHostnameIntersectWithRouteHostnames[H types.HostnameT, L types.ListenerT](listener L, hostnames []H) bool { + if len(hostnames) == 0 { return true } - // iterate over all the hostnames and check that at least one intersect with the listener hostname - for _, hostname := range hostnames { - if util.HostnamesIntersect(string(*listener.Hostname), string(hostname)) { + // if the listener has no hostname, all hostnames automatically intersect + switch l := (interface{})(listener).(type) { + case gatewayv1alpha2.Listener: + if l.Hostname == nil || *l.Hostname == "" { return true } + + // iterate over all the hostnames and check that at least one intersect with the listener hostname + for _, hostname := range hostnames { + if util.HostnamesIntersect(*l.Hostname, hostname) { + return true + } + } + case gatewayv1beta1.Listener: + if l.Hostname == nil || *l.Hostname == "" { + return true + } + + // iterate over all the hostnames and check that at least one intersect with the listener hostname + for _, hostname := range hostnames { + if util.HostnamesIntersect(*l.Hostname, hostname) { + return true + } + } } + return false } // filterHostnames accepts a HTTPRoute and returns a version of the same object with only a subset of the // hostnames, the ones matching with the listeners' hostname. -func filterHostnames(gateways []supportedGatewayWithCondition, httpRoute *gatewayv1alpha2.HTTPRoute) *gatewayv1alpha2.HTTPRoute { - filteredHostnames := make([]gatewayv1alpha2.Hostname, 0) +func filterHostnames(gateways []supportedGatewayWithCondition, httpRoute *gatewayv1beta1.HTTPRoute) *gatewayv1beta1.HTTPRoute { + filteredHostnames := make([]gatewayv1beta1.Hostname, 0) // if no hostnames are specified in the route spec, get all the hostnames from // the gateway @@ -229,7 +269,7 @@ func filterHostnames(gateways []supportedGatewayWithCondition, httpRoute *gatewa for _, listener := range gateway.gateway.Spec.Listeners { if listenerName := gatewayv1alpha2.SectionName(gateway.listenerName); listenerName == "" || listenerName == listener.Name { if listener.Hostname != nil { - filteredHostnames = append(filteredHostnames, *listener.Hostname) + filteredHostnames = append(filteredHostnames, (gatewayv1beta1.Hostname)(*listener.Hostname)) } } } @@ -253,12 +293,12 @@ func filterHostnames(gateways []supportedGatewayWithCondition, httpRoute *gatewa // - if the httpRoute hostname acts as a wildcard for the listener hostname, return the listener hostname // - if the httpRoute hostname is the same of the listener hostname, return it // - if none of the above is true, return an empty string. -func getMinimumHostnameIntersection(gateways []supportedGatewayWithCondition, hostname gatewayv1alpha2.Hostname) gatewayv1alpha2.Hostname { +func getMinimumHostnameIntersection(gateways []supportedGatewayWithCondition, hostname gatewayv1beta1.Hostname) gatewayv1beta1.Hostname { for _, gateway := range gateways { for _, listener := range gateway.gateway.Spec.Listeners { // if the listenerName is specified and matches the name of the gateway listener proceed - if gatewayv1alpha2.SectionName(gateway.listenerName) == "" || - gatewayv1alpha2.SectionName(gateway.listenerName) == listener.Name { + if (gatewayv1beta1.SectionName)(gateway.listenerName) == "" || + (gatewayv1beta1.SectionName)(gateway.listenerName) == (gatewayv1beta1.SectionName)(listener.Name) { if listener.Hostname == nil || *listener.Hostname == "" { return hostname } @@ -266,7 +306,7 @@ func getMinimumHostnameIntersection(gateways []supportedGatewayWithCondition, ho return hostname } if util.HostnamesMatch(string(hostname), string(*listener.Hostname)) { - return *listener.Hostname + return (gatewayv1beta1.Hostname)(*listener.Hostname) } } } @@ -284,9 +324,9 @@ func isRouteAccepted(gateways []supportedGatewayWithCondition) bool { } // isHTTPReferenceGranted checks that the backendRef referenced by the HTTPRoute is granted by a ReferenceGrant. -func isHTTPReferenceGranted(grantSpec gatewayv1alpha2.ReferenceGrantSpec, backendRef gatewayv1alpha2.HTTPBackendRef, fromNamespace string) bool { - var backendRefGroup gatewayv1alpha2.Group - var backendRefKind gatewayv1alpha2.Kind +func isHTTPReferenceGranted(grantSpec gatewayv1alpha2.ReferenceGrantSpec, backendRef gatewayv1beta1.HTTPBackendRef, fromNamespace string) bool { + var backendRefGroup gatewayv1beta1.Group + var backendRefKind gatewayv1beta1.Kind if backendRef.Group != nil { backendRefGroup = *backendRef.Group @@ -295,14 +335,14 @@ func isHTTPReferenceGranted(grantSpec gatewayv1alpha2.ReferenceGrantSpec, backen backendRefKind = *backendRef.Kind } for _, from := range grantSpec.From { - if from.Group != gatewayv1alpha2.GroupName || from.Kind != "HTTPRoute" || fromNamespace != string(from.Namespace) { + if from.Group != gatewayv1beta1.GroupName || from.Kind != "HTTPRoute" || fromNamespace != string(from.Namespace) { continue } for _, to := range grantSpec.To { - if backendRefGroup == to.Group && - backendRefKind == to.Kind && - (to.Name == nil || *to.Name == backendRef.Name) { + if backendRefGroup == (gatewayv1beta1.Group)(to.Group) && + backendRefKind == (gatewayv1beta1.Kind)(to.Kind) && + (to.Name == nil || (gatewayv1beta1.ObjectName)(*to.Name) == backendRef.Name) { return true } } diff --git a/internal/controllers/gateway/route_utils_test.go b/internal/controllers/gateway/route_utils_test.go index 133a786a23..68d633cbec 100644 --- a/internal/controllers/gateway/route_utils_test.go +++ b/internal/controllers/gateway/route_utils_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" ) @@ -32,8 +33,8 @@ func Test_filterHostnames(t *testing.T) { testCases := []struct { name string gateways []supportedGatewayWithCondition - httpRoute *gatewayv1alpha2.HTTPRoute - expectedHTTPRoute *gatewayv1alpha2.HTTPRoute + httpRoute *gatewayv1beta1.HTTPRoute + expectedHTTPRoute *gatewayv1beta1.HTTPRoute }{ { name: "listener 1 - specific", @@ -43,19 +44,19 @@ func Test_filterHostnames(t *testing.T) { listenerName: "listener-1", }, }, - httpRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("*.anotherwildcard.io"), - util.StringToGatewayAPIHostname("*.nonmatchingwildcard.io"), - util.StringToGatewayAPIHostname("very.specific.com"), + httpRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("*.anotherwildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("*.nonmatchingwildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("very.specific.com"), }, }, }, - expectedHTTPRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("very.specific.com"), + expectedHTTPRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("very.specific.com"), }, }, }, @@ -68,18 +69,18 @@ func Test_filterHostnames(t *testing.T) { listenerName: "listener-1", }, }, - httpRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("non.matching.com"), - util.StringToGatewayAPIHostname("*.specific.com"), + httpRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("non.matching.com"), + util.StringToGatewayAPIHostnameV1Beta1("*.specific.com"), }, }, }, - expectedHTTPRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("very.specific.com"), + expectedHTTPRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("very.specific.com"), }, }, }, @@ -92,23 +93,23 @@ func Test_filterHostnames(t *testing.T) { listenerName: "listener-2", }, }, - httpRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("non.matching.com"), - util.StringToGatewayAPIHostname("wildcard.io"), - util.StringToGatewayAPIHostname("foo.wildcard.io"), - util.StringToGatewayAPIHostname("bar.wildcard.io"), - util.StringToGatewayAPIHostname("foo.bar.wildcard.io"), + httpRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("non.matching.com"), + util.StringToGatewayAPIHostnameV1Beta1("wildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("foo.wildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("bar.wildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("foo.bar.wildcard.io"), }, }, }, - expectedHTTPRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("foo.wildcard.io"), - util.StringToGatewayAPIHostname("bar.wildcard.io"), - util.StringToGatewayAPIHostname("foo.bar.wildcard.io"), + expectedHTTPRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("foo.wildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("bar.wildcard.io"), + util.StringToGatewayAPIHostnameV1Beta1("foo.bar.wildcard.io"), }, }, }, @@ -121,17 +122,17 @@ func Test_filterHostnames(t *testing.T) { listenerName: "listener-3", }, }, - httpRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("*.anotherwildcard.io"), + httpRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("*.anotherwildcard.io"), }, }, }, - expectedHTTPRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("*.anotherwildcard.io"), + expectedHTTPRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("*.anotherwildcard.io"), }, }, }, @@ -143,17 +144,17 @@ func Test_filterHostnames(t *testing.T) { gateway: commonGateway, }, }, - httpRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ - util.StringToGatewayAPIHostname("specific.but.wrong.com"), - util.StringToGatewayAPIHostname("wildcard.io"), + httpRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ + util.StringToGatewayAPIHostnameV1Beta1("specific.but.wrong.com"), + util.StringToGatewayAPIHostnameV1Beta1("wildcard.io"), }, }, }, - expectedHTTPRoute: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{}, + expectedHTTPRoute: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{}, }, }, }, diff --git a/internal/controllers/gateway/tcproute_controller.go b/internal/controllers/gateway/tcproute_controller.go index cefa05b710..20d88da030 100644 --- a/internal/controllers/gateway/tcproute_controller.go +++ b/internal/controllers/gateway/tcproute_controller.go @@ -377,7 +377,7 @@ func (r *TCPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Conte Namespace: (*gatewayv1alpha2.Namespace)(&gateway.gateway.Namespace), Name: gatewayv1alpha2.ObjectName(gateway.gateway.Name), }, - ControllerName: ControllerName, + ControllerName: (gatewayv1alpha2.GatewayController)(ControllerName), Conditions: []metav1.Condition{{ Type: string(gatewayv1alpha2.RouteConditionAccepted), Status: metav1.ConditionTrue, @@ -433,7 +433,7 @@ func (r *TCPRouteReconciler) ensureGatewayReferenceStatusRemoved(ctx context.Con // drop all status references to supported Gateway objects newStatuses := make([]gatewayv1alpha2.RouteParentStatus, 0) for _, status := range tcproute.Status.Parents { - if status.ControllerName != ControllerName { + if status.ControllerName != (gatewayv1alpha2.GatewayController)(ControllerName) { newStatuses = append(newStatuses, status) } } diff --git a/internal/controllers/gateway/tlsroute_controller.go b/internal/controllers/gateway/tlsroute_controller.go index f9b2d46ec8..22c652daf1 100644 --- a/internal/controllers/gateway/tlsroute_controller.go +++ b/internal/controllers/gateway/tlsroute_controller.go @@ -377,7 +377,7 @@ func (r *TLSRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Conte Namespace: (*gatewayv1alpha2.Namespace)(&gateway.gateway.Namespace), Name: gatewayv1alpha2.ObjectName(gateway.gateway.Name), }, - ControllerName: ControllerName, + ControllerName: (gatewayv1alpha2.GatewayController)(ControllerName), Conditions: []metav1.Condition{{ Type: string(gatewayv1alpha2.RouteConditionAccepted), Status: metav1.ConditionTrue, @@ -433,7 +433,7 @@ func (r *TLSRouteReconciler) ensureGatewayReferenceStatusRemoved(ctx context.Con // drop all status references to supported Gateway objects newStatuses := make([]gatewayv1alpha2.RouteParentStatus, 0) for _, status := range tlsroute.Status.Parents { - if status.ControllerName != ControllerName { + if status.ControllerName != (gatewayv1alpha2.GatewayController)(ControllerName) { newStatuses = append(newStatuses, status) } } diff --git a/internal/controllers/gateway/udproute_controller.go b/internal/controllers/gateway/udproute_controller.go index eed65f7933..5c6db4c06e 100644 --- a/internal/controllers/gateway/udproute_controller.go +++ b/internal/controllers/gateway/udproute_controller.go @@ -377,7 +377,7 @@ func (r *UDPRouteReconciler) ensureGatewayReferenceStatusAdded(ctx context.Conte Namespace: (*gatewayv1alpha2.Namespace)(&gateway.gateway.Namespace), Name: gatewayv1alpha2.ObjectName(gateway.gateway.Name), }, - ControllerName: ControllerName, + ControllerName: (gatewayv1alpha2.GatewayController)(ControllerName), Conditions: []metav1.Condition{{ Type: string(gatewayv1alpha2.RouteConditionAccepted), Status: metav1.ConditionTrue, @@ -433,7 +433,7 @@ func (r *UDPRouteReconciler) ensureGatewayReferenceStatusRemoved(ctx context.Con // drop all status references to supported Gateway objects newStatuses := make([]gatewayv1alpha2.RouteParentStatus, 0) for _, status := range udproute.Status.Parents { - if status.ControllerName != ControllerName { + if status.ControllerName != (gatewayv1alpha2.GatewayController)(ControllerName) { newStatuses = append(newStatuses, status) } } diff --git a/internal/dataplane/kongstate/util_test.go b/internal/dataplane/kongstate/util_test.go index 8d5ad81c0f..a00055fc4d 100644 --- a/internal/dataplane/kongstate/util_test.go +++ b/internal/dataplane/kongstate/util_test.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" @@ -508,7 +509,7 @@ func TestGetKongIngressFromObjectMeta(t *testing.T) { }, { name: "konghq.com/override annotation does not affect Gateway API's HTTPRoute", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ TypeMeta: metav1.TypeMeta{ Kind: "HTTPRoute", APIVersion: "gateway.networking.k8s.io/v1alpha2", diff --git a/internal/dataplane/parser/parser.go b/internal/dataplane/parser/parser.go index 5aad22a539..b39a7d6a43 100644 --- a/internal/dataplane/parser/parser.go +++ b/internal/dataplane/parser/parser.go @@ -468,7 +468,8 @@ func getGatewayCerts(log logrus.FieldLogger, s store.Storer) []certWrapper { Kind: gatewayv1alpha2.Kind(gateway.GetObjectKind().GroupVersionKind().Kind), Namespace: gatewayv1alpha2.Namespace(gateway.GetNamespace()), }, grants) - if !isRefAllowedByGrant(ref.Namespace, ref.Name, ref.Group, ref.Kind, allowed) { + + if !newRefChecker(ref).IsRefAllowedByGrant(allowed) { log.WithFields(logrus.Fields{ "gateway": gateway.Name, "gateway_namespace": gateway.Namespace, diff --git a/internal/dataplane/parser/translate_httproute.go b/internal/dataplane/parser/translate_httproute.go index f32d5755fd..24768a3c1e 100644 --- a/internal/dataplane/parser/translate_httproute.go +++ b/internal/dataplane/parser/translate_httproute.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/kong/go-kong/kong" - gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" @@ -46,7 +46,7 @@ func (p *Parser) ingressRulesFromHTTPRoutes() ingressRules { return result } -func (p *Parser) ingressRulesFromHTTPRoute(result *ingressRules, httproute *gatewayv1alpha2.HTTPRoute) error { +func (p *Parser) ingressRulesFromHTTPRoute(result *ingressRules, httproute *gatewayv1beta1.HTTPRoute) error { // first we grab the spec and gather some metadata about the object spec := httproute.Spec @@ -75,12 +75,12 @@ func (p *Parser) ingressRulesFromHTTPRoute(result *ingressRules, httproute *gate } // create a service and attach the routes to it - var backendRefs []gatewayv1alpha2.BackendRef + var backendRefs []gatewayv1beta1.BackendRef // HTTPRoute uses a wrapper HTTPBackendRef to add optional filters to its BackendRefs for _, hRef := range rule.BackendRefs { backendRefs = append(backendRefs, hRef.BackendRef) } - service, err := p.generateKongServiceFromBackendRef(result, httproute, ruleNumber, "http", backendRefs...) + service, err := generateKongServiceFromBackendRef(p.logger, p.storer, result, httproute, ruleNumber, "http", backendRefs...) if err != nil { return err } @@ -100,7 +100,7 @@ func (p *Parser) ingressRulesFromHTTPRoute(result *ingressRules, httproute *gate // getHTTPRouteHostnamesAsSliceOfStringPointers translates the hostnames defined // in an HTTPRoute specification into a []*string slice, which is the type required // by kong.Route{}. -func getHTTPRouteHostnamesAsSliceOfStringPointers(httproute *gatewayv1alpha2.HTTPRoute) []*string { +func getHTTPRouteHostnamesAsSliceOfStringPointers(httproute *gatewayv1beta1.HTTPRoute) []*string { hostnames := make([]*string, 0, len(httproute.Spec.Hostnames)) for _, hostname := range httproute.Spec.Hostnames { hostnames = append(hostnames, kong.String(string(hostname))) @@ -115,7 +115,7 @@ func getHTTPRouteHostnamesAsSliceOfStringPointers(httproute *gatewayv1alpha2.HTT // path prefix routing option for that service in addition to hostname routing. // If an HTTPRoute is provided that has matches that include any unsupported matching // configurations, this will produce an error and the route is considered invalid. -func generateKongRoutesFromHTTPRouteRule(httproute *gatewayv1alpha2.HTTPRoute, ruleNumber int, rule gatewayv1alpha2.HTTPRouteRule) ([]kongstate.Route, error) { +func generateKongRoutesFromHTTPRouteRule(httproute *gatewayv1beta1.HTTPRoute, ruleNumber int, rule gatewayv1beta1.HTTPRouteRule) ([]kongstate.Route, error) { // gather the k8s object information and hostnames from the httproute objectInfo := util.FromK8sObject(httproute) hostnames := getHTTPRouteHostnamesAsSliceOfStringPointers(httproute) @@ -165,10 +165,12 @@ func generateKongRoutesFromHTTPRouteRule(httproute *gatewayv1alpha2.HTTPRoute, r // default it it is not. For those types, we use the path value as-is and let Kong determine the type. // For exact matches, we transform the path into a regular expression that terminates after the value if match.Path != nil { - if *match.Path.Type == gatewayv1alpha2.PathMatchExact { + switch *match.Path.Type { + case gatewayv1beta1.PathMatchExact: terminated := *match.Path.Value + "$" r.Route.Paths = []*string{&terminated} - } else if *match.Path.Type == gatewayv1alpha2.PathMatchRegularExpression || *match.Path.Type == gatewayv1alpha2.PathMatchPathPrefix { + case gatewayv1beta1.PathMatchRegularExpression, + gatewayv1beta1.PathMatchPathPrefix: r.Route.Paths = []*string{match.Path.Value} } } @@ -239,14 +241,14 @@ func generateKongRoutesFromHTTPRouteRule(httproute *gatewayv1alpha2.HTTPRoute, r // generatePluginsFromHTTPRouteRuleFilters accepts a rule as argument and converts // HttpRouteRule.Filters into Kong filters. -func generatePluginsFromHTTPRouteRuleFilters(rule gatewayv1alpha2.HTTPRouteRule) []kong.Plugin { +func generatePluginsFromHTTPRouteRuleFilters(rule gatewayv1beta1.HTTPRouteRule) []kong.Plugin { kongPlugins := make([]kong.Plugin, 0) if rule.Filters == nil { return kongPlugins } for _, filter := range rule.Filters { - if filter.Type == gatewayv1alpha2.HTTPRouteFilterRequestHeaderModifier { + if filter.Type == gatewayv1beta1.HTTPRouteFilterRequestHeaderModifier { kongPlugins = append(kongPlugins, generateRequestHeaderModifierKongPlugin(filter.RequestHeaderModifier)) } // TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/2793 @@ -255,9 +257,9 @@ func generatePluginsFromHTTPRouteRuleFilters(rule gatewayv1alpha2.HTTPRouteRule) return kongPlugins } -// generateRequestHeaderModifierKongPlugin converts a gatewayv1alpha2.HTTPRequestHeaderFilter into a +// generateRequestHeaderModifierKongPlugin converts a gatewayv1beta1.HTTPRequestHeaderFilter into a // kong.Plugin of type request-transformer. -func generateRequestHeaderModifierKongPlugin(modifier *gatewayv1alpha2.HTTPRequestHeaderFilter) kong.Plugin { +func generateRequestHeaderModifierKongPlugin(modifier *gatewayv1beta1.HTTPRequestHeaderFilter) kong.Plugin { plugin := kong.Plugin{ Name: kong.String("request-transformer"), Config: make(kong.Configuration), @@ -297,6 +299,6 @@ func generateRequestHeaderModifierKongPlugin(modifier *gatewayv1alpha2.HTTPReque return plugin } -func kongHeaderFormatter(header gatewayv1alpha2.HTTPHeader) string { +func kongHeaderFormatter(header gatewayv1beta1.HTTPHeader) string { return fmt.Sprintf("%s:%s", header.Name, header.Value) } diff --git a/internal/dataplane/parser/translate_httproute_test.go b/internal/dataplane/parser/translate_httproute_test.go index 0a4e7c9221..d3d256fbfe 100644 --- a/internal/dataplane/parser/translate_httproute_test.go +++ b/internal/dataplane/parser/translate_httproute_test.go @@ -11,7 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/utils/pointer" - gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" @@ -31,15 +31,15 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { fakestore, err := store.NewFakeStore(store.FakeObjects{}) assert.NoError(t, err) p := NewParser(logrus.New(), fakestore) - httpPort := gatewayv1alpha2.PortNumber(80) - pathMatchPrefix := gatewayv1alpha2.PathMatchPathPrefix - pathMatchRegex := gatewayv1alpha2.PathMatchRegularExpression - pathMatchExact := gatewayv1alpha2.PathMatchExact - queryMatchExact := gatewayv1alpha2.QueryParamMatchExact + httpPort := gatewayv1beta1.PortNumber(80) + pathMatchPrefix := gatewayv1beta1.PathMatchPathPrefix + pathMatchRegex := gatewayv1beta1.PathMatchRegularExpression + pathMatchExact := gatewayv1beta1.PathMatchExact + queryMatchExact := gatewayv1beta1.QueryParamMatchExact for _, tt := range []struct { msg string - routes []*gatewayv1alpha2.HTTPRoute + routes []*gatewayv1beta1.HTTPRoute expected ingressRules errs []error }{ @@ -52,28 +52,28 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "an HTTPRoute rule with no matches can be routed if it has hostnames to match on", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, - Hostnames: []gatewayv1alpha2.Hostname{ + Hostnames: []gatewayv1beta1.Hostname{ "konghq.com", "www.konghq.com", }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + Rules: []gatewayv1beta1.HTTPRouteRule{{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }}, @@ -125,28 +125,28 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, }, }}, - Parent: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{ + Parent: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{ { - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Name: gatewayv1beta1.ObjectName("fake-gateway"), }, }, }, - Hostnames: []gatewayv1alpha2.Hostname{ - gatewayv1alpha2.Hostname("konghq.com"), - gatewayv1alpha2.Hostname("www.konghq.com"), + Hostnames: []gatewayv1beta1.Hostname{ + gatewayv1beta1.Hostname("konghq.com"), + gatewayv1beta1.Hostname("www.konghq.com"), }, - Rules: []gatewayv1alpha2.HTTPRouteRule{ + Rules: []gatewayv1beta1.HTTPRouteRule{ { - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }, @@ -169,24 +169,24 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "an HTTPRoute rule with no matches and no hostnames can't be routed", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, // no hostnames present - Rules: []gatewayv1alpha2.HTTPRouteRule{{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ // no match rules present - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, }, }, @@ -204,30 +204,30 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "a single HTTPRoute with one match and one backendRef results in a single service", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Path: &gatewayv1alpha2.HTTPPathMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchPrefix, Value: kong.String("/httpbin"), }, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }}, @@ -279,32 +279,32 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, }, }}, - Parent: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{ + Parent: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{ { - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Name: gatewayv1beta1.ObjectName("fake-gateway"), }, }, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{ + Rules: []gatewayv1beta1.HTTPRouteRule{ { - Matches: []gatewayv1alpha2.HTTPRouteMatch{ + Matches: []gatewayv1beta1.HTTPRouteMatch{ { - Path: &gatewayv1alpha2.HTTPPathMatch{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchPrefix, Value: kong.String("/httpbin"), }, }, }, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }, @@ -327,15 +327,15 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "an HTTPRoute with no rules can't be routed", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, }, @@ -350,31 +350,31 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "an HTTPRoute with queryParam matches is not yet supported", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - QueryParams: []gatewayv1alpha2.HTTPQueryParamMatch{{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + QueryParams: []gatewayv1beta1.HTTPQueryParamMatch{{ Type: &queryMatchExact, Name: "username", Value: "kong", }}, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }}, @@ -391,30 +391,30 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "an HTTPRoute with regex path matches is supported", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Path: &gatewayv1alpha2.HTTPPathMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchRegex, Value: kong.String("/httpbin$"), }, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }}, @@ -466,32 +466,32 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, }, }}, - Parent: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{ + Parent: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{ { - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Name: gatewayv1beta1.ObjectName("fake-gateway"), }, }, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{ + Rules: []gatewayv1beta1.HTTPRouteRule{ { - Matches: []gatewayv1alpha2.HTTPRouteMatch{ + Matches: []gatewayv1beta1.HTTPRouteMatch{ { - Path: &gatewayv1alpha2.HTTPPathMatch{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchRegex, Value: kong.String("/httpbin$"), }, }, }, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }, @@ -514,30 +514,30 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, { msg: "an HTTPRoute with exact path matches translates to a terminated Kong regex route", - routes: []*gatewayv1alpha2.HTTPRoute{{ + routes: []*gatewayv1beta1.HTTPRoute{{ ObjectMeta: metav1.ObjectMeta{ Name: "basic-httproute", Namespace: corev1.NamespaceDefault, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Path: &gatewayv1alpha2.HTTPPathMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchExact, Value: kong.String("/httpbin"), }, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }}, @@ -589,32 +589,32 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { }, }, }}, - Parent: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{ + Parent: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{ { - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Name: gatewayv1beta1.ObjectName("fake-gateway"), }, }, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{ + Rules: []gatewayv1beta1.HTTPRouteRule{ { - Matches: []gatewayv1alpha2.HTTPRouteMatch{ + Matches: []gatewayv1beta1.HTTPRouteMatch{ { - Path: &gatewayv1alpha2.HTTPPathMatch{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchExact, Value: kong.String("/httpbin"), }, }, }, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("fake-service"), + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("fake-service"), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }, @@ -663,19 +663,19 @@ func Test_ingressRulesFromHTTPRoutes(t *testing.T) { func Test_getHTTPRouteHostnamesAsSliceOfStringPointers(t *testing.T) { for _, tt := range []struct { msg string - input *gatewayv1alpha2.HTTPRoute + input *gatewayv1beta1.HTTPRoute expected []*string }{ { msg: "an HTTPRoute with no hostnames produces no hostnames", - input: &gatewayv1alpha2.HTTPRoute{}, + input: &gatewayv1beta1.HTTPRoute{}, expected: []*string{}, }, { msg: "an HTTPRoute with a single hostname produces a list with that one hostname", - input: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ + input: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ "konghq.com", }, }, @@ -686,9 +686,9 @@ func Test_getHTTPRouteHostnamesAsSliceOfStringPointers(t *testing.T) { }, { msg: "an HTTPRoute with multiple hostnames produces a list with the same hostnames", - input: &gatewayv1alpha2.HTTPRoute{ - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Hostnames: []gatewayv1alpha2.Hostname{ + input: &gatewayv1beta1.HTTPRoute{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Hostnames: []gatewayv1beta1.Hostname{ "konghq.com", "www.konghq.com", "docs.konghq.com", diff --git a/internal/dataplane/parser/translate_tcproute.go b/internal/dataplane/parser/translate_tcproute.go index 7c265faaf6..9c4f8daba2 100644 --- a/internal/dataplane/parser/translate_tcproute.go +++ b/internal/dataplane/parser/translate_tcproute.go @@ -71,7 +71,7 @@ func (p *Parser) ingressRulesFromTCPRoute(result *ingressRules, tcproute *gatewa } // create a service and attach the routes to it - service, err := p.generateKongServiceFromBackendRef(result, tcproute, ruleNumber, "tcp", rule.BackendRefs...) + service, err := generateKongServiceFromBackendRef(p.logger, p.storer, result, tcproute, ruleNumber, "tcp", rule.BackendRefs...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_tlsroute.go b/internal/dataplane/parser/translate_tlsroute.go index f66c639298..ab4a738c72 100644 --- a/internal/dataplane/parser/translate_tlsroute.go +++ b/internal/dataplane/parser/translate_tlsroute.go @@ -63,7 +63,7 @@ func (p *Parser) ingressRulesFromTLSRoute(result *ingressRules, tlsroute *gatewa } // create a service and attach the routes to it - service, err := p.generateKongServiceFromBackendRef(result, tlsroute, ruleNumber, "tcp", rule.BackendRefs...) + service, err := generateKongServiceFromBackendRef(p.logger, p.storer, result, tlsroute, ruleNumber, "tcp", rule.BackendRefs...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_udproute.go b/internal/dataplane/parser/translate_udproute.go index 61a9d0a834..c2a9b5e5ec 100644 --- a/internal/dataplane/parser/translate_udproute.go +++ b/internal/dataplane/parser/translate_udproute.go @@ -71,7 +71,7 @@ func (p *Parser) ingressRulesFromUDPRoute(result *ingressRules, udproute *gatewa } // create a service and attach the routes to it - service, err := p.generateKongServiceFromBackendRef(result, udproute, ruleNumber, "udp", rule.BackendRefs...) + service, err := generateKongServiceFromBackendRef(p.logger, p.storer, result, udproute, ruleNumber, "udp", rule.BackendRefs...) if err != nil { return err } diff --git a/internal/dataplane/parser/translate_utils.go b/internal/dataplane/parser/translate_utils.go index f7008c21ea..87890c2ac4 100644 --- a/internal/dataplane/parser/translate_utils.go +++ b/internal/dataplane/parser/translate_utils.go @@ -6,10 +6,14 @@ import ( "github.com/blang/semver/v4" "github.com/kong/go-kong/kong" + "github.com/sirupsen/logrus" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" + "github.com/kong/kubernetes-ingress-controller/v2/internal/store" + "github.com/kong/kubernetes-ingress-controller/v2/internal/types" "github.com/kong/kubernetes-ingress-controller/v2/internal/util" ) @@ -26,7 +30,7 @@ var MinRegexHeaderKongVersion = semver.MustParse("2.8.0") // convertGatewayMatchHeadersToKongRouteMatchHeaders takes an input list of Gateway APIs HTTPHeaderMatch // and converts these header matching rules to the format expected by go-kong. -func convertGatewayMatchHeadersToKongRouteMatchHeaders(headers []gatewayv1alpha2.HTTPHeaderMatch) (map[string][]string, error) { +func convertGatewayMatchHeadersToKongRouteMatchHeaders(headers []gatewayv1beta1.HTTPHeaderMatch) (map[string][]string, error) { // iterate through each provided header match checking for invalid // options and otherwise converting to kong type format. convertedHeaders := make(map[string][]string) @@ -35,13 +39,13 @@ func convertGatewayMatchHeadersToKongRouteMatchHeaders(headers []gatewayv1alpha2 return nil, fmt.Errorf("multiple header matches for the same header are not allowed: %s", string(header.Name)) } - if header.Type != nil && *header.Type == gatewayv1alpha2.HeaderMatchRegularExpression { + if header.Type != nil && *header.Type == gatewayv1beta1.HeaderMatchRegularExpression { if util.GetKongVersion().LT(MinRegexHeaderKongVersion) { return nil, fmt.Errorf("Kong version %s does not support HeaderMatchRegularExpression", util.GetKongVersion().String()) } convertedHeaders[string(header.Name)] = []string{kongHeaderRegexPrefix + header.Value} - } else if header.Type == nil || *header.Type == gatewayv1alpha2.HeaderMatchExact { + } else if header.Type == nil || *header.Type == gatewayv1beta1.HeaderMatchExact { convertedHeaders[string(header.Name)] = []string{header.Value} } else { return nil, fmt.Errorf("unknown/unsupported header match type: %s", string(*header.Type)) @@ -51,43 +55,14 @@ func convertGatewayMatchHeadersToKongRouteMatchHeaders(headers []gatewayv1alpha2 return convertedHeaders, nil } -// isRefAllowedByGrant checks if backendRef is permitted by the provided namespace-indexed ReferenceGrantTo set, -// allowed. allowed is assumed to contain Tos that only match the backendRef's parent's From, as returned by -// getPermittedForReferenceGrantFrom. -func isRefAllowedByGrant( - namespace *gatewayv1alpha2.Namespace, - name gatewayv1alpha2.ObjectName, - group *gatewayv1alpha2.Group, - kind *gatewayv1alpha2.Kind, - allowed map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo, -) bool { - if namespace == nil { - // local references are always fine - return true - } - for _, to := range allowed[*namespace] { - if to.Group == *group && to.Kind == *kind { - if to.Name != nil { - if *to.Name == name { - return true - } - } else { - // if no referent name specified, matching group/kind is sufficient - return true - } - } - } - - return false -} - // getPermittedForReferenceGrantFrom takes a ReferenceGrant From (a namespace, group, and kind) and returns a map // from a namespace to a slice of ReferenceGrant Tos. When a To is included in the slice, the key namespace has a // ReferenceGrant with those Tos and the input From. -func getPermittedForReferenceGrantFrom(from gatewayv1alpha2.ReferenceGrantFrom, +func getPermittedForReferenceGrantFrom( + from gatewayv1alpha2.ReferenceGrantFrom, grants []*gatewayv1alpha2.ReferenceGrant, -) map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo { - allowed := make(map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo) +) map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo { + allowed := make(map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo) // loop over all From values in all grants. if we find a match, add all Tos to the list of Tos allowed for the // grant namespace. this technically could add duplicate copies of the Tos if there are duplicate Froms (it makes // no sense to add them, but it's allowed), but duplicate Tos are harmless (we only care about having at least one @@ -95,7 +70,7 @@ func getPermittedForReferenceGrantFrom(from gatewayv1alpha2.ReferenceGrantFrom, for _, grant := range grants { for _, otherFrom := range grant.Spec.From { if reflect.DeepEqual(from, otherFrom) { - allowed[gatewayv1alpha2.Namespace(grant.ObjectMeta.Namespace)] = append(allowed[gatewayv1alpha2.Namespace(grant.ObjectMeta.Namespace)], grant.Spec.To...) + allowed[gatewayv1beta1.Namespace(grant.ObjectMeta.Namespace)] = append(allowed[gatewayv1beta1.Namespace(grant.ObjectMeta.Namespace)], grant.Spec.To...) } } } @@ -105,12 +80,16 @@ func getPermittedForReferenceGrantFrom(from gatewayv1alpha2.ReferenceGrantFrom, // generateKongServiceFromBackendRef translates backendRefs for rule ruleNumber into a Kong service for use with the // rules generated from a Gateway APIs route. -func (p *Parser) generateKongServiceFromBackendRef( +func generateKongServiceFromBackendRef[ + T types.BackendRefT, +]( + logger logrus.FieldLogger, + storer store.Storer, rules *ingressRules, route client.Object, ruleNumber int, protocol string, - backendRefs ...gatewayv1alpha2.BackendRef, + backendRefs ...T, ) (kongstate.Service, error) { objName := fmt.Sprintf("%s %s/%s", route.GetObjectKind().GroupVersionKind().String(), route.GetNamespace(), route.GetName()) @@ -118,9 +97,7 @@ func (p *Parser) generateKongServiceFromBackendRef( return kongstate.Service{}, fmt.Errorf("no backendRefs present for %s, cannot build Kong service", objName) } - backends := make(kongstate.ServiceBackends, 0, len(backendRefs)) - - grants, err := p.storer.ListReferenceGrants() + grants, err := storer.ListReferenceGrants() if err != nil { return kongstate.Service{}, fmt.Errorf("could not retrieve ReferenceGrants for %s: %w", objName, err) } @@ -130,37 +107,7 @@ func (p *Parser) generateKongServiceFromBackendRef( Namespace: gatewayv1alpha2.Namespace(route.GetNamespace()), }, grants) - for _, backendRef := range backendRefs { - if util.IsBackendRefGroupKindSupported(backendRef.Group, backendRef.Kind) && - isRefAllowedByGrant(backendRef.Namespace, backendRef.Name, backendRef.Group, backendRef.Kind, allowed) { - backend := kongstate.ServiceBackend{ - Name: string(backendRef.Name), - PortDef: kongstate.PortDef{ - Mode: kongstate.PortModeByNumber, - Number: int32(*backendRef.Port), - }, - Weight: backendRef.Weight, - } - if backendRef.Namespace != nil { - backend.Namespace = string(*backendRef.Namespace) - } - backends = append(backends, backend) - } else { - // 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) - var namespace, kind string = route.GetNamespace(), "" - if backendRef.Namespace != nil { - namespace = string(*backendRef.Namespace) - } - if backendRef.Kind != nil { - kind = string(*backendRef.Kind) - } - p.logger.Errorf("%s requested backendRef to %s %s/%s, but no ReferenceGrant permits it, skipping...", - objName, kind, namespace, backendRef.Name) - } - } + backends := backendRefsToKongStateBackends(logger, route, backendRefs, allowed) // the service name needs to uniquely identify this service given it's list of // one or more backends. diff --git a/internal/dataplane/parser/translate_utils_test.go b/internal/dataplane/parser/translate_utils_test.go index c0eaeee64b..1fecd57b02 100644 --- a/internal/dataplane/parser/translate_utils_test.go +++ b/internal/dataplane/parser/translate_utils_test.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" "github.com/kong/kubernetes-ingress-controller/v2/internal/store" @@ -19,11 +20,11 @@ import ( ) func Test_convertGatewayMatchHeadersToKongRouteMatchHeadersVersionBehavior(t *testing.T) { - regexType := gatewayv1alpha2.HeaderMatchRegularExpression + regexType := gatewayv1beta1.HeaderMatchRegularExpression type Case struct { msg string - input []gatewayv1alpha2.HTTPHeaderMatch + input []gatewayv1beta1.HTTPHeaderMatch output map[string][]string err error } @@ -32,7 +33,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeadersVersionBehavior(t *te belowThresholdTests := []Case{ { msg: "regex header matches fail on unsupported versions", - input: []gatewayv1alpha2.HTTPHeaderMatch{{ + input: []gatewayv1beta1.HTTPHeaderMatch{{ Type: ®exType, Name: "Content-Type", Value: "^audio/*", @@ -42,7 +43,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeadersVersionBehavior(t *te }, { msg: "a single exact header match succeeds on any version", - input: []gatewayv1alpha2.HTTPHeaderMatch{{ + input: []gatewayv1beta1.HTTPHeaderMatch{{ Name: "Content-Type", Value: "audio/vorbis", }}, @@ -65,7 +66,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeadersVersionBehavior(t *te aboveThresholdTests := []Case{ { msg: "regex header matches succeed on supported versions", - input: []gatewayv1alpha2.HTTPHeaderMatch{{ + input: []gatewayv1beta1.HTTPHeaderMatch{{ Type: ®exType, Name: "Content-Type", Value: "^audio/*", @@ -86,20 +87,20 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeadersVersionBehavior(t *te } func Test_convertGatewayMatchHeadersToKongRouteMatchHeaders(t *testing.T) { - regexType := gatewayv1alpha2.HeaderMatchRegularExpression - exactType := gatewayv1alpha2.HeaderMatchExact + regexType := gatewayv1beta1.HeaderMatchRegularExpression + exactType := gatewayv1beta1.HeaderMatchExact util.SetKongVersion(semver.MustParse("2.8.0")) t.Log("generating several gateway header matches") tests := []struct { msg string - input []gatewayv1alpha2.HTTPHeaderMatch + input []gatewayv1beta1.HTTPHeaderMatch output map[string][]string err error }{ { msg: "regex header matches convert correctly", - input: []gatewayv1alpha2.HTTPHeaderMatch{{ + input: []gatewayv1beta1.HTTPHeaderMatch{{ Type: ®exType, Name: "Content-Type", Value: "^audio/*", @@ -110,7 +111,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeaders(t *testing.T) { }, { msg: "a single exact header match with no type defaults to exact type and converts properly", - input: []gatewayv1alpha2.HTTPHeaderMatch{{ + input: []gatewayv1beta1.HTTPHeaderMatch{{ Name: "Content-Type", Value: "audio/vorbis", }}, @@ -120,7 +121,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeaders(t *testing.T) { }, { msg: "a single exact header match with a single value converts properly", - input: []gatewayv1alpha2.HTTPHeaderMatch{{ + input: []gatewayv1beta1.HTTPHeaderMatch{{ Type: &exactType, Name: "Content-Type", Value: "audio/vorbis", @@ -131,7 +132,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeaders(t *testing.T) { }, { msg: "multiple header matches for the same header are rejected", - input: []gatewayv1alpha2.HTTPHeaderMatch{ + input: []gatewayv1beta1.HTTPHeaderMatch{ { Name: "Content-Type", Value: "audio/vorbis", @@ -146,7 +147,7 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeaders(t *testing.T) { }, { msg: "multiple header matches convert properly", - input: []gatewayv1alpha2.HTTPHeaderMatch{ + input: []gatewayv1beta1.HTTPHeaderMatch{ { Type: &exactType, Name: "Content-Type", @@ -179,44 +180,54 @@ func Test_convertGatewayMatchHeadersToKongRouteMatchHeaders(t *testing.T) { } func Test_isRefAllowedByGrant(t *testing.T) { - fitrat := gatewayv1alpha2.Namespace("fitrat") - cholpon := gatewayv1alpha2.Namespace("cholpon") - behbudiy := gatewayv1alpha2.Namespace("behbudiy") + fitrat := gatewayv1beta1.Namespace("fitrat") + cholpon := gatewayv1beta1.Namespace("cholpon") + behbudiy := gatewayv1beta1.Namespace("behbudiy") - group := gatewayv1alpha2.Group("fake.example.com") - kind := gatewayv1alpha2.Kind("fakeKind") - badKind := gatewayv1alpha2.Kind("badFakeKind") - cholponName := gatewayv1alpha2.ObjectName("cholpon") + group := gatewayv1beta1.Group("fake.example.com") + kind := gatewayv1beta1.Kind("fakeKind") + badKind := gatewayv1beta1.Kind("badFakeKind") + cholponName := gatewayv1beta1.ObjectName("cholpon") - fakeMap := map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{ - fitrat: {{Group: group, Kind: kind}, {Group: gatewayv1alpha2.Group("extra.example"), Kind: badKind}}, - cholpon: {{Group: group, Kind: kind, Name: &cholponName}}, + refGrantGroup := gatewayv1alpha2.Group(group) + refGrantKind := gatewayv1alpha2.Kind(kind) + refGrantBadKind := gatewayv1alpha2.Kind(badKind) + refGrantName := gatewayv1alpha2.ObjectName(cholponName) + + fakeMap := map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{ + fitrat: { + {Group: refGrantGroup, Kind: refGrantKind}, + {Group: gatewayv1alpha2.Group("extra.example"), Kind: refGrantBadKind}, + }, + cholpon: { + {Group: refGrantGroup, Kind: refGrantKind, Name: &refGrantName}, + }, behbudiy: {}, } tests := []struct { msg string - ref gatewayv1alpha2.BackendRef + ref gatewayv1beta1.BackendRef result bool }{ { msg: "empty", - ref: gatewayv1alpha2.BackendRef{}, + ref: gatewayv1beta1.BackendRef{}, result: true, }, { msg: "no namespace", - ref: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("foo"), + ref: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("foo"), }, }, result: true, }, { msg: "valid namespace+group+kind", - ref: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("foo"), + ref: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("foo"), Group: &group, Kind: &kind, Namespace: &fitrat, @@ -226,8 +237,8 @@ func Test_isRefAllowedByGrant(t *testing.T) { }, { msg: "valid namespace+group+kind+name", - ref: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + ref: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: cholponName, Group: &group, Kind: &kind, @@ -238,9 +249,9 @@ func Test_isRefAllowedByGrant(t *testing.T) { }, { msg: "invalid namespace+group+kind", - ref: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("foo"), + ref: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("foo"), Group: &group, Kind: &badKind, Namespace: &fitrat, @@ -250,9 +261,9 @@ func Test_isRefAllowedByGrant(t *testing.T) { }, { msg: "invalid namespace+group+kind+name", - ref: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("sadness"), + ref: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("sadness"), Group: &group, Kind: &kind, Namespace: &cholpon, @@ -262,9 +273,9 @@ func Test_isRefAllowedByGrant(t *testing.T) { }, { msg: "no grants in target namespace", - ref: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName("foo"), + ref: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName("foo"), Group: &group, Kind: &kind, Namespace: &behbudiy, @@ -275,7 +286,8 @@ func Test_isRefAllowedByGrant(t *testing.T) { } for _, tt := range tests { t.Run(tt.msg, func(t *testing.T) { - result := isRefAllowedByGrant(tt.ref.Namespace, tt.ref.Name, tt.ref.Group, tt.ref.Kind, fakeMap) + result := newRefChecker(tt.ref).IsRefAllowedByGrant(fakeMap) + assert.Equal(t, tt.result, result) }) } @@ -346,7 +358,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { tests := []struct { msg string from gatewayv1alpha2.ReferenceGrantFrom - result map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo + result map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo }{ { msg: "no matches whatsoever", @@ -355,7 +367,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { Kind: gatewayv1alpha2.Kind("invalid"), Namespace: gatewayv1alpha2.Namespace("invalid"), }, - result: map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, + result: map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, }, { msg: "non-matching namespace", @@ -364,7 +376,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { Kind: gatewayv1alpha2.Kind("UDPRoute"), Namespace: gatewayv1alpha2.Namespace("niyazi"), }, - result: map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, + result: map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, }, { msg: "non-matching kind", @@ -373,7 +385,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { Kind: gatewayv1alpha2.Kind("TLSRoute"), Namespace: gatewayv1alpha2.Namespace("behbudiy"), }, - result: map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, + result: map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, }, { msg: "non-matching group", @@ -382,7 +394,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { Kind: gatewayv1alpha2.Kind("UDPRoute"), Namespace: gatewayv1alpha2.Namespace("behbudiy"), }, - result: map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, + result: map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{}, }, { msg: "single match", @@ -391,7 +403,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { Kind: gatewayv1alpha2.Kind("UDPRoute"), Namespace: gatewayv1alpha2.Namespace("behbudiy"), }, - result: map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{ + result: map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{ "cholpon": { { Group: gatewayv1alpha2.Group(""), @@ -407,7 +419,7 @@ func Test_getPermittedForReferenceGrantFrom(t *testing.T) { Kind: gatewayv1alpha2.Kind("TCPRoute"), Namespace: gatewayv1alpha2.Namespace("qodiriy"), }, - result: map[gatewayv1alpha2.Namespace][]gatewayv1alpha2.ReferenceGrantTo{ + result: map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo{ "cholpon": { { Group: gatewayv1alpha2.Group(""), @@ -501,29 +513,29 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { rules := ingressRules{ServiceNameToServices: map[string]kongstate.Service{}} ruleNumber := 999 protocol := "example" - port := gatewayv1alpha2.PortNumber(7777) - redObjName := gatewayv1alpha2.ObjectName("red-service") - blueObjName := gatewayv1alpha2.ObjectName("blue-service") - cholponNamespace := gatewayv1alpha2.Namespace("cholpon") - serviceKind := gatewayv1alpha2.Kind("Service") - serviceGroup := gatewayv1alpha2.Group("") + port := gatewayv1beta1.PortNumber(7777) + redObjName := gatewayv1beta1.ObjectName("red-service") + blueObjName := gatewayv1beta1.ObjectName("blue-service") + cholponNamespace := gatewayv1beta1.Namespace("cholpon") + serviceKind := gatewayv1beta1.Kind("Service") + serviceGroup := gatewayv1beta1.Group("") tests := []struct { msg string route client.Object - refs []gatewayv1alpha2.BackendRef + refs []gatewayv1beta1.BackendRef result kongstate.Service wantErr bool }{ { msg: "empty backend list", - route: &gatewayv1alpha2.HTTPRoute{}, - refs: []gatewayv1alpha2.BackendRef{}, + route: &gatewayv1beta1.HTTPRoute{}, + refs: []gatewayv1beta1.BackendRef{}, result: kongstate.Service{}, wantErr: true, }, { msg: "all backends in route namespace", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ // normally the k8s api call populates TypeMeta properly, but we have no such luxuries here TypeMeta: metav1.TypeMeta{ Kind: "HTTPRoute", @@ -534,9 +546,9 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { Namespace: "cholpon", }, }, - refs: []gatewayv1alpha2.BackendRef{ + refs: []gatewayv1beta1.BackendRef{ { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: blueObjName, Kind: &serviceKind, Port: &port, @@ -544,7 +556,7 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { }, }, { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: redObjName, Kind: &serviceKind, Port: &port, @@ -579,7 +591,7 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { }, }, }, - Parent: &gatewayv1alpha2.HTTPRoute{ + Parent: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: "tong-sirlari", Namespace: "cholpon", @@ -604,9 +616,9 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { Namespace: "behbudiy", }, }, - refs: []gatewayv1alpha2.BackendRef{ + refs: []gatewayv1beta1.BackendRef{ { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: blueObjName, Port: &port, Kind: &serviceKind, @@ -615,7 +627,7 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { }, }, { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: redObjName, Port: &port, Kind: &serviceKind, @@ -676,9 +688,9 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { Namespace: "behbudiy", }, }, - refs: []gatewayv1alpha2.BackendRef{ + refs: []gatewayv1beta1.BackendRef{ { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: blueObjName, Port: &port, Kind: &serviceKind, @@ -733,9 +745,9 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { Namespace: "behbudiy", }, }, - refs: []gatewayv1alpha2.BackendRef{ + refs: []gatewayv1beta1.BackendRef{ { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: blueObjName, Port: &port, Kind: &serviceKind, @@ -744,7 +756,7 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { }, }, { - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: redObjName, Port: &port, Kind: &serviceKind, @@ -788,7 +800,7 @@ func Test_generateKongServiceFromBackendRef(t *testing.T) { } for _, tt := range tests { t.Run(tt.msg, func(t *testing.T) { - result, err := p.generateKongServiceFromBackendRef(&rules, tt.route, ruleNumber, protocol, tt.refs...) + result, err := generateKongServiceFromBackendRef(p.logger, p.storer, &rules, tt.route, ruleNumber, protocol, tt.refs...) assert.Equal(t, tt.result, result) if tt.wantErr { assert.NotNil(t, err) diff --git a/internal/dataplane/parser/wrappers_backendref.go b/internal/dataplane/parser/wrappers_backendref.go new file mode 100644 index 0000000000..a4ee63da90 --- /dev/null +++ b/internal/dataplane/parser/wrappers_backendref.go @@ -0,0 +1,144 @@ +package parser + +import ( + "fmt" + + "github.com/sirupsen/logrus" + "sigs.k8s.io/controller-runtime/pkg/client" + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" + + "github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" + "github.com/kong/kubernetes-ingress-controller/v2/internal/types" + "github.com/kong/kubernetes-ingress-controller/v2/internal/util" +) + +type backendRefWrapper[T types.BackendRefT] struct { + backendRef T +} + +func newBackendRefWrapper[T types.BackendRefT](b T) backendRefWrapper[T] { + return backendRefWrapper[T]{ + backendRef: b, + } +} + +func (brw backendRefWrapper[T]) Group() *gatewayv1beta1.Group { + switch br := (interface{})(brw.backendRef).(type) { + case gatewayv1alpha2.BackendRef: + return (*gatewayv1beta1.Group)(br.Group) + case gatewayv1beta1.BackendRef: + return br.Group + } + return nil +} + +func (brw backendRefWrapper[T]) Kind() *gatewayv1beta1.Kind { + switch br := (interface{})(brw.backendRef).(type) { + case gatewayv1alpha2.BackendRef: + return (*gatewayv1beta1.Kind)(br.Kind) + case gatewayv1beta1.BackendRef: + return br.Kind + } + return nil +} + +func (brw backendRefWrapper[T]) Name() string { + switch br := (interface{})(brw.backendRef).(type) { + case gatewayv1alpha2.BackendRef: + return string(br.Name) + case gatewayv1beta1.BackendRef: + return string(br.Name) + } + return "" +} + +func (brw backendRefWrapper[T]) Namespace() *string { + switch br := (interface{})(brw.backendRef).(type) { + case gatewayv1alpha2.BackendRef: + return (*string)(br.Namespace) + case gatewayv1beta1.BackendRef: + return (*string)(br.Namespace) + } + return nil +} + +func (brw backendRefWrapper[T]) Port() int32 { + switch br := (interface{})(brw.backendRef).(type) { + case gatewayv1alpha2.BackendRef: + if br.Port == nil { + return -1 + } + return int32(*br.Port) + case gatewayv1beta1.BackendRef: + if br.Port == nil { + return -1 + } + return int32(*br.Port) + } + return -1 +} + +func (brw backendRefWrapper[T]) Weight() *int32 { + switch br := (interface{})(brw.backendRef).(type) { + case gatewayv1alpha2.BackendRef: + return br.Weight + case gatewayv1beta1.BackendRef: + return br.Weight + } + return nil +} + +func backendRefsToKongStateBackends[T types.BackendRefT]( + logger logrus.FieldLogger, + route client.Object, + backendRefs []T, + allowed map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo, +) kongstate.ServiceBackends { + backends := kongstate.ServiceBackends{} + + for _, backendRef := range backendRefs { + brw := newBackendRefWrapper(backendRef) + + if util.IsBackendRefGroupKindSupported( + brw.Group(), + brw.Kind(), + ) && newRefChecker(backendRef).IsRefAllowedByGrant(allowed) { + + backend := kongstate.ServiceBackend{ + Name: brw.Name(), + PortDef: kongstate.PortDef{ + Mode: kongstate.PortModeByNumber, + Number: brw.Port(), + }, + Weight: brw.Weight(), + } + if brw.Namespace() != nil { + backend.Namespace = *brw.Namespace() + } + backends = append(backends, backend) + } else { + // 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) + var namespace, kind string = route.GetNamespace(), "" + if brw.Namespace() != nil { + namespace = *brw.Namespace() + } + if brw.Kind() != nil { + kind = string(*brw.Kind()) + } + + objName := fmt.Sprintf("%s %s/%s", + route.GetObjectKind().GroupVersionKind().String(), + route.GetNamespace(), + route.GetName()) + logger.Errorf( + "%s requested backendRef to %s %s/%s, but no ReferenceGrant permits it, skipping...", + objName, kind, namespace, brw.Name()) + } + } + + return backends +} diff --git a/internal/dataplane/parser/wrappers_refchecker.go b/internal/dataplane/parser/wrappers_refchecker.go new file mode 100644 index 0000000000..1ab79b396f --- /dev/null +++ b/internal/dataplane/parser/wrappers_refchecker.go @@ -0,0 +1,100 @@ +package parser + +import ( + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" + + "github.com/kong/kubernetes-ingress-controller/v2/internal/types" +) + +// refChecker is a wrapper type that facilitates checking whether a backenRef is allowed +// by a referenceGrantTo set. +type refChecker[T types.BackendRefT] struct { + backendRef T +} + +func newRefChecker[T types.BackendRefT](ref T) refChecker[T] { + return refChecker[T]{ + backendRef: ref, + } +} + +// IsRefAllowedByGrant is a wrapper on top of isRefAllowedByGrant checks if backendRef (that RefChecker +// holds) is permitted by the provided namespace-indexed ReferenceGrantTo set: allowedRefs. +// allowedRefs is assumed to contain Tos that only match the backendRef's parent's From, as returned by +// getPermittedForReferenceGrantFrom. +func (rc refChecker[T]) IsRefAllowedByGrant( + allowedRefs map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo, +) bool { + switch br := (interface{})(rc.backendRef).(type) { + case gatewayv1beta1.BackendRef: + if br.Namespace == nil { + return true + } + + return isRefAllowedByGrant( + (*string)(br.Namespace), + (string)(br.Name), + (string)(*br.Group), + (string)(*br.Kind), + allowedRefs, + ) + case gatewayv1alpha2.BackendRef: + if br.Namespace == nil { + return true + } + + return isRefAllowedByGrant( + (*string)(br.Namespace), + (string)(br.Name), + (string)(*br.Group), + (string)(*br.Kind), + allowedRefs, + ) + + case gatewayv1alpha2.SecretObjectReference: + if br.Namespace == nil { + return true + } + + return isRefAllowedByGrant( + (*string)(br.Namespace), + (string)(br.Name), + (string)(*br.Group), + (string)(*br.Kind), + allowedRefs, + ) + } + + return false +} + +// isRefAllowedByGrant checks if backendRef is permitted by the provided namespace-indexed ReferenceGrantTo set: allowed. +// allowed is assumed to contain Tos that only match the backendRef's parent's From, as returned by +// getPermittedForReferenceGrantFrom. +func isRefAllowedByGrant( + namespace *string, + name string, + group string, + kind string, + allowed map[gatewayv1beta1.Namespace][]gatewayv1alpha2.ReferenceGrantTo, +) bool { + if namespace == nil { + // local references are always fine + return true + } + for _, to := range allowed[gatewayv1beta1.Namespace(*namespace)] { + if string(to.Group) == group && string(to.Kind) == kind { + if to.Name != nil { + if string(*to.Name) == name { + return true + } + } else { + // if no referent name specified, matching group/kind is sufficient + return true + } + } + } + + return false +} diff --git a/internal/store/fake_store.go b/internal/store/fake_store.go index e5d84285a3..3f31c0d431 100644 --- a/internal/store/fake_store.go +++ b/internal/store/fake_store.go @@ -10,6 +10,7 @@ import ( "k8s.io/client-go/tools/cache" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" configurationv1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" @@ -34,7 +35,7 @@ type FakeObjects struct { IngressesV1beta1 []*netv1beta1.Ingress IngressesV1 []*netv1.Ingress IngressClassesV1 []*netv1.IngressClass - HTTPRoutes []*gatewayv1alpha2.HTTPRoute + HTTPRoutes []*gatewayv1beta1.HTTPRoute UDPRoutes []*gatewayv1alpha2.UDPRoute TCPRoutes []*gatewayv1alpha2.TCPRoute TLSRoutes []*gatewayv1alpha2.TLSRoute diff --git a/internal/store/fake_store_test.go b/internal/store/fake_store_test.go index ad4123efaf..349f515d90 100644 --- a/internal/store/fake_store_test.go +++ b/internal/store/fake_store_test.go @@ -13,6 +13,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" configurationv1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1" @@ -732,18 +733,18 @@ func TestFakeStoreHTTPRoute(t *testing.T) { assert := assert.New(t) require := require.New(t) - classes := []*gatewayv1alpha2.HTTPRoute{ + classes := []*gatewayv1beta1.HTTPRoute{ { ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{}, + Spec: gatewayv1beta1.HTTPRouteSpec{}, }, { ObjectMeta: metav1.ObjectMeta{ Name: "bar", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{}, + Spec: gatewayv1beta1.HTTPRouteSpec{}, }, } store, err := NewFakeStore(FakeObjects{HTTPRoutes: classes}) diff --git a/internal/store/store.go b/internal/store/store.go index d1f6bc3c4a..82e2d60b02 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -40,6 +40,7 @@ import ( "k8s.io/client-go/tools/cache" knative "knative.dev/networking/pkg/apis/networking/v1alpha1" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "sigs.k8s.io/yaml" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" @@ -85,7 +86,7 @@ type Storer interface { ListIngressesV1() []*netv1.Ingress ListIngressClassesV1() []*netv1.IngressClass ListIngressClassParametersV1Alpha1() []*kongv1alpha1.IngressClassParameters - ListHTTPRoutes() ([]*gatewayv1alpha2.HTTPRoute, error) + ListHTTPRoutes() ([]*gatewayv1beta1.HTTPRoute, error) ListUDPRoutes() ([]*gatewayv1alpha2.UDPRoute, error) ListTCPRoutes() ([]*gatewayv1alpha2.TCPRoute, error) ListTLSRoutes() ([]*gatewayv1alpha2.TLSRoute, error) @@ -253,7 +254,7 @@ func (c CacheStores) Get(obj runtime.Object) (item interface{}, exists bool, err // ---------------------------------------------------------------------------- // Kubernetes Gateway API Support // ---------------------------------------------------------------------------- - case *gatewayv1alpha2.HTTPRoute: + case *gatewayv1beta1.HTTPRoute: return c.HTTPRoute.Get(obj) case *gatewayv1alpha2.UDPRoute: return c.UDPRoute.Get(obj) @@ -318,7 +319,7 @@ func (c CacheStores) Add(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kubernetes Gateway API Support // ---------------------------------------------------------------------------- - case *gatewayv1alpha2.HTTPRoute: + case *gatewayv1beta1.HTTPRoute: return c.HTTPRoute.Add(obj) case *gatewayv1alpha2.UDPRoute: return c.UDPRoute.Add(obj) @@ -384,7 +385,7 @@ func (c CacheStores) Delete(obj runtime.Object) error { // ---------------------------------------------------------------------------- // Kubernetes Gateway API Support // ---------------------------------------------------------------------------- - case *gatewayv1alpha2.HTTPRoute: + case *gatewayv1beta1.HTTPRoute: return c.HTTPRoute.Delete(obj) case *gatewayv1alpha2.UDPRoute: return c.UDPRoute.Delete(obj) @@ -586,11 +587,11 @@ func (s Store) ListIngressesV1beta1() []*netv1beta1.Ingress { } // ListHTTPRoutes returns the list of HTTPRoutes in the HTTPRoute cache store. -func (s Store) ListHTTPRoutes() ([]*gatewayv1alpha2.HTTPRoute, error) { - var httproutes []*gatewayv1alpha2.HTTPRoute +func (s Store) ListHTTPRoutes() ([]*gatewayv1beta1.HTTPRoute, error) { + var httproutes []*gatewayv1beta1.HTTPRoute if err := cache.ListAll(s.stores.HTTPRoute, labels.NewSelector(), func(ob interface{}) { - httproute, ok := ob.(*gatewayv1alpha2.HTTPRoute) + httproute, ok := ob.(*gatewayv1beta1.HTTPRoute) if ok { httproutes = append(httproutes, httproute) } @@ -1048,7 +1049,7 @@ func mkObjFromGVK(gvk schema.GroupVersionKind) (runtime.Object, error) { // Kubernetes Gateway APIs // ---------------------------------------------------------------------------- case gatewayv1alpha2.SchemeGroupVersion.WithKind("HTTPRoutes"): - return &gatewayv1alpha2.HTTPRoute{}, nil + return &gatewayv1beta1.HTTPRoute{}, nil // ---------------------------------------------------------------------------- // Kong APIs // ---------------------------------------------------------------------------- diff --git a/internal/types/types.go b/internal/types/types.go new file mode 100644 index 0000000000..913a594938 --- /dev/null +++ b/internal/types/types.go @@ -0,0 +1,32 @@ +package types + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" +) + +type HostnameT interface { + gatewayv1beta1.Hostname | gatewayv1alpha2.Hostname | string +} + +type ListenerT interface { + gatewayv1beta1.Listener | gatewayv1alpha2.Listener +} + +type RouteT interface { + client.Object + + *gatewayv1beta1.HTTPRoute | + *gatewayv1alpha2.UDPRoute | + *gatewayv1alpha2.TCPRoute | + *gatewayv1alpha2.TLSRoute +} + +type ParentReferenceT interface { + gatewayv1alpha2.ParentReference | gatewayv1beta1.ParentReference +} + +type BackendRefT interface { + gatewayv1beta1.BackendRef | gatewayv1alpha2.BackendRef | gatewayv1alpha2.SecretObjectReference +} diff --git a/internal/util/conversions.go b/internal/util/conversions.go index 5d5a394470..4e2c6b3f76 100644 --- a/internal/util/conversions.go +++ b/internal/util/conversions.go @@ -3,6 +3,7 @@ package util import ( "k8s.io/utils/pointer" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) // ----------------------------------------------------------------------------- @@ -14,11 +15,21 @@ func StringToGatewayAPIHostname(hostname string) gatewayv1alpha2.Hostname { return (gatewayv1alpha2.Hostname)(hostname) } +// StringToGatewayAPIHostnameV1Beta1 converts a string to a gatewayv1beta1.Hostname. +func StringToGatewayAPIHostnameV1Beta1(hostname string) gatewayv1beta1.Hostname { + return (gatewayv1beta1.Hostname)(hostname) +} + // StringToGatewayAPIHostnamePtr converts a string to a *gatewayv1alpha2.Hostname. func StringToGatewayAPIHostnamePtr(hostname string) *gatewayv1alpha2.Hostname { return (*gatewayv1alpha2.Hostname)(pointer.StringPtr(hostname)) } +// StringToGatewayAPIHostnameV1Beta1Ptr converts a string to a *gatewayv1beta1.Hostname. +func StringToGatewayAPIHostnameV1Beta1Ptr(hostname string) *gatewayv1beta1.Hostname { + return (*gatewayv1beta1.Hostname)(pointer.StringPtr(hostname)) +} + // StringToGatewayAPIKind converts a string to a gatewayv1alpha2.Kind. func StringToGatewayAPIKind(kind string) gatewayv1alpha2.Kind { return (gatewayv1alpha2.Kind)(kind) @@ -28,3 +39,8 @@ func StringToGatewayAPIKind(kind string) gatewayv1alpha2.Kind { func StringToGatewayAPIKindPtr(kind string) *gatewayv1alpha2.Kind { return (*gatewayv1alpha2.Kind)(pointer.StringPtr(kind)) } + +// StringToGatewayAPIKindV1Beta1Ptr converts a string to a *gatewayv1beta1.Kind. +func StringToGatewayAPIKindV1Beta1Ptr(kind string) *gatewayv1beta1.Kind { + return (*gatewayv1beta1.Kind)(pointer.StringPtr(kind)) +} diff --git a/internal/util/hostname.go b/internal/util/hostname.go index 78be7043a9..970d2da950 100644 --- a/internal/util/hostname.go +++ b/internal/util/hostname.go @@ -1,13 +1,21 @@ package util -import "strings" +import ( + "strings" + + "github.com/kong/kubernetes-ingress-controller/v2/internal/types" +) // HostnamesIntersect checks if the hostnameA and hostnameB have an intersection. // To perform this check, the function HostnamesMatch is called twice swapping the // parameters and using first hostnameA as a mask, then hostnameB. // If there is at least one match, the hostnames intersect. -func HostnamesIntersect(hostnameA, hostnameB string) bool { - return HostnamesMatch(hostnameA, hostnameB) || HostnamesMatch(hostnameB, hostnameA) +func HostnamesIntersect[H1, H2 types.HostnameT](hostnameA H1, hostnameB H2) bool { + var ( + a = (string)(hostnameA) + b = (string)(hostnameB) + ) + return HostnamesMatch(a, b) || HostnamesMatch(b, a) } // HostnamesMatch checks that the hostnameB matches the hostnameA. HostnameA is treated as mask diff --git a/internal/util/k8s.go b/internal/util/k8s.go index acfe0fa92b..8174eb9ad3 100644 --- a/internal/util/k8s.go +++ b/internal/util/k8s.go @@ -25,7 +25,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clientset "k8s.io/client-go/kubernetes" - gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) // ParseNameNS parses a string searching a namespace and name. @@ -115,7 +115,7 @@ var backendRefSupportedGroupKinds = map[string]struct{}{ // IsBackendRefGroupKindSupported checks if the GroupKind of the object used as // BackendRef for the HTTPRoute is supported. -func IsBackendRefGroupKindSupported(gatewayAPIGroup *gatewayv1alpha2.Group, gatewayAPIKind *gatewayv1alpha2.Kind) bool { +func IsBackendRefGroupKindSupported(gatewayAPIGroup *gatewayv1beta1.Group, gatewayAPIKind *gatewayv1beta1.Kind) bool { if gatewayAPIKind == nil { return false } diff --git a/internal/validation/gateway/httproute.go b/internal/validation/gateway/httproute.go index d737232876..fd2537b665 100644 --- a/internal/validation/gateway/httproute.go +++ b/internal/validation/gateway/httproute.go @@ -4,6 +4,7 @@ import ( "fmt" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) // ----------------------------------------------------------------------------- @@ -13,7 +14,7 @@ import ( // ValidateHTTPRoute provides a suite of validation for a given HTTPRoute and // any number of Gateway resources it's attached to that the caller wants to // have it validated against. -func ValidateHTTPRoute(httproute *gatewayv1alpha2.HTTPRoute, attachedGateways ...*gatewayv1alpha2.Gateway) (bool, string, error) { +func ValidateHTTPRoute(httproute *gatewayv1beta1.HTTPRoute, attachedGateways ...*gatewayv1alpha2.Gateway) (bool, string, error) { // perform Gateway validations for the HTTPRoute (e.g. listener validation, namespace validation, e.t.c.) for _, gateway := range attachedGateways { // TODO: validate that the namespace is supported by the linked Gateway objects @@ -77,7 +78,7 @@ func validateHTTPRouteListener(listener *gatewayv1alpha2.Listener) error { // validateHTTPRouteFeatures checks for features that are not supported by this // HTTPRoute implementation and validates that the provided object is not using // any of those unsupported features. -func validateHTTPRouteFeatures(httproute *gatewayv1alpha2.HTTPRoute) error { +func validateHTTPRouteFeatures(httproute *gatewayv1beta1.HTTPRoute) error { for _, rule := range httproute.Spec.Rules { for _, match := range rule.Matches { // we don't support queryparam matching rules @@ -88,14 +89,14 @@ func validateHTTPRouteFeatures(httproute *gatewayv1alpha2.HTTPRoute) error { // we don't support regex path matching rules // See: https://github.com/Kong/kubernetes-ingress-controller/issues/2153 - if match.Path != nil && match.Path.Type != nil && *match.Path.Type == gatewayv1alpha2.PathMatchRegularExpression { + if match.Path != nil && match.Path.Type != nil && *match.Path.Type == gatewayv1beta1.PathMatchRegularExpression { return fmt.Errorf("regex path matching is not yet supported for httproute") } // we don't support regex header matching rules // See: https://github.com/Kong/kubernetes-ingress-controller/issues/2154 for _, hdr := range match.Headers { - if hdr.Type != nil && *hdr.Type == gatewayv1alpha2.HeaderMatchRegularExpression { + if hdr.Type != nil && *hdr.Type == gatewayv1beta1.HeaderMatchRegularExpression { return fmt.Errorf("regex header matching is not yet supported for httproute") } } @@ -122,7 +123,7 @@ func validateHTTPRouteFeatures(httproute *gatewayv1alpha2.HTTPRoute) error { // which links to the provided Gateway if available. If the provided Gateway is not // actually referenced by parentRef in the provided HTTPRoute this is considered // invalid input and will produce an error. -func getParentRefForHTTPRouteGateway(httproute *gatewayv1alpha2.HTTPRoute, gateway *gatewayv1alpha2.Gateway) (*gatewayv1alpha2.ParentReference, error) { +func getParentRefForHTTPRouteGateway(httproute *gatewayv1beta1.HTTPRoute, gateway *gatewayv1alpha2.Gateway) (*gatewayv1beta1.ParentReference, error) { // search all the parentRefs on the HTTPRoute to find one that matches the Gateway for _, ref := range httproute.Spec.ParentRefs { // determine the namespace for the gateway reference @@ -144,13 +145,13 @@ func getParentRefForHTTPRouteGateway(httproute *gatewayv1alpha2.HTTPRoute, gatew // getListenersForHTTPRouteValidation determines if ALL http listeners should be used for validation // or if only a select listener should be considered. -func getListenersForHTTPRouteValidation(sectionName *gatewayv1alpha2.SectionName, gateway *gatewayv1alpha2.Gateway) ([]*gatewayv1alpha2.Listener, error) { +func getListenersForHTTPRouteValidation(sectionName *gatewayv1beta1.SectionName, gateway *gatewayv1alpha2.Gateway) ([]*gatewayv1alpha2.Listener, error) { var listenersForValidation []*gatewayv1alpha2.Listener if sectionName != nil { // only one specified listener is in use, only need to validate the // route against that listener. for _, listener := range gateway.Spec.Listeners { - if listener.Name == *sectionName { + if string(listener.Name) == string(*sectionName) { listenerCopy := listener listenersForValidation = append(listenersForValidation, &listenerCopy) } @@ -165,7 +166,8 @@ func getListenersForHTTPRouteValidation(sectionName *gatewayv1alpha2.SectionName // no specific listener was chosen, so we'll simply validate against // all HTTP listeners on the Gateway. for _, listener := range gateway.Spec.Listeners { - if listener.Protocol == gatewayv1alpha2.HTTPProtocolType || listener.Protocol == gatewayv1alpha2.HTTPSProtocolType { + if (gatewayv1beta1.ProtocolType)(listener.Protocol) == gatewayv1beta1.HTTPProtocolType || + (gatewayv1beta1.ProtocolType)(listener.Protocol) == gatewayv1beta1.HTTPSProtocolType { listenerCopy := listener listenersForValidation = append(listenersForValidation, &listenerCopy) } diff --git a/internal/validation/gateway/httproute_test.go b/internal/validation/gateway/httproute_test.go index 6abedafe9f..31e728010a 100644 --- a/internal/validation/gateway/httproute_test.go +++ b/internal/validation/gateway/httproute_test.go @@ -9,20 +9,23 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) func TestValidateHTTPRoute(t *testing.T) { - nonexistentListener := gatewayv1alpha2.SectionName("listener-that-doesnt-exist") - group := gatewayv1alpha2.Group("gateway.networking.k8s.io") - defaultGWNamespace := gatewayv1alpha2.Namespace(corev1.NamespaceDefault) - pathMatchRegex := gatewayv1alpha2.PathMatchRegularExpression - headerMatchRegex := gatewayv1alpha2.HeaderMatchRegularExpression - exampleGroup := gatewayv1alpha2.Group("example") - podKind := gatewayv1alpha2.Kind("Pod") + var ( + nonexistentListener = gatewayv1beta1.SectionName("listener-that-doesnt-exist") + group = gatewayv1alpha2.Group("gateway.networking.k8s.io") + defaultGWNamespace = gatewayv1beta1.Namespace(corev1.NamespaceDefault) + pathMatchRegex = gatewayv1beta1.PathMatchRegularExpression + headerMatchRegex = gatewayv1beta1.HeaderMatchRegularExpression + exampleGroup = gatewayv1beta1.Group("example") + podKind = gatewayv1beta1.Kind("Pod") + ) for _, tt := range []struct { msg string - route *gatewayv1alpha2.HTTPRoute + route *gatewayv1beta1.HTTPRoute gateways []*gatewayv1alpha2.Gateway valid bool validationMsg string @@ -30,7 +33,7 @@ func TestValidateHTTPRoute(t *testing.T) { }{ { msg: "if you provide errant gateways for validation, it fails validation", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", @@ -45,7 +48,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -61,14 +64,14 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "if you use sectionname to attach to a non-existent gateway listener, it fails validation", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", SectionName: &nonexistentListener, }}, @@ -84,7 +87,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "not-the-right-listener", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -100,14 +103,14 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "if the provided gateway has NO listeners, the HTTPRoute fails validation", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, @@ -128,14 +131,14 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "parentRefs which omit the namespace pass validation in the same namespace", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, @@ -150,7 +153,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -164,14 +167,14 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "if the gateway listener doesn't support HTTPRoute, validation fails", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, @@ -186,7 +189,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http-alternate", Port: 8000, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -202,27 +205,27 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "if an HTTPRoute is using queryparams matching it fails validation due to lack of support", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - QueryParams: []gatewayv1alpha2.HTTPQueryParamMatch{{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + QueryParams: []gatewayv1beta1.HTTPQueryParamMatch{{ Name: "user-agent", Value: "netscape navigator", }}, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Namespace: &defaultGWNamespace, }, }, @@ -239,7 +242,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -255,27 +258,27 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "if an HTTPRoute is using regex path matching it fails validation due to lack of support", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Path: &gatewayv1alpha2.HTTPPathMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchRegex, Value: kong.String("^path/to/stuff/*$"), }, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Namespace: &defaultGWNamespace, }, }, @@ -292,7 +295,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -308,28 +311,28 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "if an HTTPRoute is using regex header matching it fails validation due to lack of support", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Headers: []gatewayv1alpha2.HTTPHeaderMatch{{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Headers: []gatewayv1beta1.HTTPHeaderMatch{{ Type: &headerMatchRegex, Name: "Content-Type", Value: "audio/vorbis", }}, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Namespace: &defaultGWNamespace, }, }, @@ -346,7 +349,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -362,28 +365,28 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "we don't support any group except core kubernetes for backendRefs", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Headers: []gatewayv1alpha2.HTTPHeaderMatch{{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Headers: []gatewayv1beta1.HTTPHeaderMatch{{ Name: "Content-Type", Value: "audio/vorbis", }}, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Group: &exampleGroup, Kind: &podKind, Namespace: &defaultGWNamespace, @@ -404,7 +407,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, @@ -420,28 +423,28 @@ func TestValidateHTTPRoute(t *testing.T) { }, { msg: "we don't support any core kind except Service for backendRefs", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Namespace: corev1.NamespaceDefault, Name: "testing-httproute", }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ Name: "testing-gateway", }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Headers: []gatewayv1alpha2.HTTPHeaderMatch{{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Headers: []gatewayv1beta1.HTTPHeaderMatch{{ Name: "Content-Type", Value: "audio/vorbis", }}, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{ + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Kind: &podKind, Namespace: &defaultGWNamespace, Name: "service1", @@ -461,7 +464,7 @@ func TestValidateHTTPRoute(t *testing.T) { Listeners: []gatewayv1alpha2.Listener{{ Name: "http", Port: 80, - Protocol: gatewayv1alpha2.HTTPProtocolType, + Protocol: (gatewayv1alpha2.ProtocolType)(gatewayv1beta1.HTTPProtocolType), AllowedRoutes: &gatewayv1alpha2.AllowedRoutes{ Kinds: []gatewayv1alpha2.RouteGroupKind{{ Group: &group, diff --git a/test/conformance/gateway_conformance_test.go b/test/conformance/gateway_conformance_test.go index 48e68e9c40..6fa6458b12 100644 --- a/test/conformance/gateway_conformance_test.go +++ b/test/conformance/gateway_conformance_test.go @@ -42,7 +42,7 @@ func TestGatewayConformance(t *testing.T) { Name: uuid.NewString(), }, Spec: gatewayv1beta1.GatewayClassSpec{ - ControllerName: gatewayv1beta1.GatewayController(gateway.ControllerName), + ControllerName: gateway.ControllerName, }, } require.NoError(t, client.Create(ctx, gwc)) diff --git a/test/e2e/helpers_gateway_test.go b/test/e2e/helpers_gateway_test.go index 4c1f01abc5..d02025e662 100644 --- a/test/e2e/helpers_gateway_test.go +++ b/test/e2e/helpers_gateway_test.go @@ -42,7 +42,7 @@ func deployGateway(ctx context.Context, t *testing.T, env environments.Environme Name: uuid.NewString(), }, Spec: gatewayv1beta1.GatewayClassSpec{ - ControllerName: gatewayv1beta1.GatewayController(gateway.ControllerName), + ControllerName: gateway.ControllerName, }, } supportedGatewayClass, err = gc.GatewayV1beta1().GatewayClasses().Create(ctx, supportedGatewayClass, metav1.CreateOptions{}) @@ -99,7 +99,7 @@ func deployGatewayWithTCPListener(ctx context.Context, t *testing.T, env environ Name: uuid.NewString(), }, Spec: gatewayv1beta1.GatewayClassSpec{ - ControllerName: gatewayv1beta1.GatewayController(gateway.ControllerName), + ControllerName: gateway.ControllerName, }, } supportedGatewayClass, err = gc.GatewayV1beta1().GatewayClasses().Create(ctx, supportedGatewayClass, metav1.CreateOptions{}) @@ -158,33 +158,33 @@ func deployHTTPRoute(ctx context.Context, t *testing.T, env environments.Environ require.NoError(t, err) t.Logf("creating an HTTPRoute for service %s with Gateway %s", service.Name, gw.Name) - pathMatchPrefix := gatewayv1alpha2.PathMatchPathPrefix + pathMatchPrefix := gatewayv1beta1.PathMatchPathPrefix path := "/httpbin" - httpPort := gatewayv1alpha2.PortNumber(80) - httproute := &gatewayv1alpha2.HTTPRoute{ + httpPort := gatewayv1beta1.PortNumber(80) + httproute := &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: uuid.NewString(), Annotations: map[string]string{ annotations.AnnotationPrefix + annotations.StripPathKey: "true", }, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName(gw.Name), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName(gw.Name), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Path: &gatewayv1alpha2.HTTPPathMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchPrefix, Value: &path, }, }}, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName(service.Name), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName(service.Name), Port: &httpPort, }, }, @@ -192,7 +192,7 @@ func deployHTTPRoute(ctx context.Context, t *testing.T, env environments.Environ }}, }, } - _, err = gc.GatewayV1alpha2().HTTPRoutes(corev1.NamespaceDefault).Create(ctx, httproute, metav1.CreateOptions{}) + _, err = gc.GatewayV1beta1().HTTPRoutes(corev1.NamespaceDefault).Create(ctx, httproute, metav1.CreateOptions{}) require.NoError(t, err) } diff --git a/test/integration/gateway_test.go b/test/integration/gateway_test.go index 3a9154bb9f..4db296867a 100644 --- a/test/integration/gateway_test.go +++ b/test/integration/gateway_test.go @@ -519,57 +519,57 @@ func TestGatewayFilters(t *testing.T) { httpPort := gatewayv1alpha2.PortNumber(80) pathMatchPrefix := gatewayv1alpha2.PathMatchPathPrefix refNamespace := gatewayv1alpha2.Namespace(gateway.Namespace) - httprouteTemplate := &gatewayv1alpha2.HTTPRoute{ + httprouteTemplate := &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: uuid.NewString(), Annotations: map[string]string{ annotations.AnnotationPrefix + annotations.StripPathKey: "true", }, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName(gateway.Name), - Namespace: &refNamespace, + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName(gateway.Name), + Namespace: (*gatewayv1beta1.Namespace)(&refNamespace), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{ { - Path: &gatewayv1alpha2.HTTPPathMatch{ - Type: &pathMatchPrefix, + Path: &gatewayv1beta1.HTTPPathMatch{ + Type: (*gatewayv1beta1.PathMatchType)(&pathMatchPrefix), Value: kong.String("/test_gateway_filters"), }, }, }, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName(service.Name), - Port: &httpPort, + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName(service.Name), + Port: (*gatewayv1beta1.PortNumber)(&httpPort), }, }, }}, }}, }, } - httpRoute, err := gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Create(ctx, httprouteTemplate, metav1.CreateOptions{}) + httpRoute, err := gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Create(ctx, httprouteTemplate, metav1.CreateOptions{}) require.NoError(t, err) - otherRoute, err := gatewayClient.GatewayV1alpha2().HTTPRoutes(other.Name).Create(ctx, httprouteTemplate, metav1.CreateOptions{}) + otherRoute, err := gatewayClient.GatewayV1beta1().HTTPRoutes(other.Name).Create(ctx, httprouteTemplate, metav1.CreateOptions{}) require.NoError(t, err) otherRoute.Spec.Rules[0].Matches[0].Path.Value = kong.String("/other_test_gateway_filters") - _, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(other.Name).Update(ctx, otherRoute, metav1.UpdateOptions{}) + _, err = gatewayClient.GatewayV1beta1().HTTPRoutes(other.Name).Update(ctx, otherRoute, metav1.UpdateOptions{}) require.NoError(t, err) defer func() { t.Logf("cleaning up the httproute %s", httpRoute.Name) - if err := gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Delete(ctx, httpRoute.Name, metav1.DeleteOptions{}); err != nil { + if err := gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Delete(ctx, httpRoute.Name, metav1.DeleteOptions{}); err != nil { if !errors.IsNotFound(err) { assert.NoError(t, err) } } - if err := gatewayClient.GatewayV1alpha2().HTTPRoutes(other.Name).Delete(ctx, httpRoute.Name, metav1.DeleteOptions{}); err != nil { + if err := gatewayClient.GatewayV1beta1().HTTPRoutes(other.Name).Delete(ctx, httpRoute.Name, metav1.DeleteOptions{}); err != nil { if !errors.IsNotFound(err) { assert.NoError(t, err) } diff --git a/test/integration/helpers_test.go b/test/integration/helpers_test.go index ff246c289c..407522d91e 100644 --- a/test/integration/helpers_test.go +++ b/test/integration/helpers_test.go @@ -41,7 +41,7 @@ func DeployGatewayClass(ctx context.Context, client *gatewayclient.Clientset, ga Name: gatewayClassName, }, Spec: gatewayv1beta1.GatewayClassSpec{ - ControllerName: gatewayv1beta1.GatewayController(gateway.ControllerName), + ControllerName: gateway.ControllerName, }, } @@ -151,59 +151,88 @@ func GetGatewayIsUnlinkedCallback(t *testing.T, c *gatewayclient.Clientset, prot } } +type routeParentStatusT interface { + gatewayv1alpha2.RouteParentStatus | gatewayv1beta1.RouteParentStatus +} + +type routeParents[T routeParentStatusT] struct { + parents []T +} + +func newRouteParentsStatus[T routeParentStatusT](parents []T) routeParents[T] { + return routeParents[T]{ + parents: parents, + } +} + +func (rp routeParents[T]) check(verifyLinked bool, controllerName string) bool { + for _, ps := range rp.parents { + switch parentStatus := (interface{})(ps).(type) { + case gatewayv1alpha2.RouteParentStatus: + if string(parentStatus.ControllerName) == controllerName { + // supported Gateway link was found, hence if we want to ensure + // the link existence return true + return verifyLinked + } + case gatewayv1beta1.RouteParentStatus: + if string(parentStatus.ControllerName) == controllerName { + // supported Gateway link was found, hence if we want to ensure + // the link existence return true + return verifyLinked + } + } + } + + // supported Gateway link was not found, hence if we want to ensure + // the link existence return false + return !verifyLinked +} + // gatewayLinkStatusMatches checks if the specific Route (HTTP, TCP, TLS, or UDP) // is correctly linked to (or unlinked from) a supported gateway. In order to assert // that the route must be linked to the gateway, or unlinked from the gateway, the // verifyLinked boolean arg must be set accordingly. func gatewayLinkStatusMatches(t *testing.T, c *gatewayclient.Clientset, verifyLinked bool, protocolType gatewayv1alpha2.ProtocolType, namespace, name string) bool { - var routeParents []gatewayv1alpha2.RouteParentStatus - // gather a fresh copy of the route, given the specific protocol type switch protocolType { //nolint:exhaustive case gatewayv1alpha2.HTTPProtocolType: - route, err := c.GatewayV1alpha2().HTTPRoutes(namespace).Get(ctx, name, metav1.GetOptions{}) + route, err := c.GatewayV1beta1().HTTPRoutes(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Logf("error getting http route: %v", err) } else { - routeParents = route.Status.Parents + return newRouteParentsStatus(route.Status.Parents). + check(verifyLinked, string(gateway.ControllerName)) } case gatewayv1alpha2.TCPProtocolType: route, err := c.GatewayV1alpha2().TCPRoutes(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Logf("error getting tcp route: %v", err) } else { - routeParents = route.Status.Parents + return newRouteParentsStatus(route.Status.Parents). + check(verifyLinked, string(gateway.ControllerName)) } case gatewayv1alpha2.UDPProtocolType: route, err := c.GatewayV1alpha2().UDPRoutes(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Logf("error getting udp route: %v", err) } else { - routeParents = route.Status.Parents + return newRouteParentsStatus(route.Status.Parents). + check(verifyLinked, string(gateway.ControllerName)) } case gatewayv1alpha2.TLSProtocolType: route, err := c.GatewayV1alpha2().TLSRoutes(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Logf("error getting tls route: %v", err) } else { - routeParents = route.Status.Parents + return newRouteParentsStatus(route.Status.Parents). + check(verifyLinked, string(gateway.ControllerName)) } default: t.Fatalf("protocol %s not supported", string(protocolType)) } - // determine if there is a link to a supported Gateway - for _, parentStatus := range routeParents { - if parentStatus.ControllerName == gateway.ControllerName { - // supported Gateway link was found, hence if we want to ensure - // the link existence return true - return verifyLinked - } - } - - // supported Gateway link was not found, hence if we want to ensure - // the link existence return false - return !verifyLinked + t.Fatal("this should not happen") + return false } // setIngressClassNameWithRetry changes Ingress.Spec.IngressClassName to specified value diff --git a/test/integration/httproute_test.go b/test/integration/httproute_test.go index ed86f005a8..ca407125b8 100644 --- a/test/integration/httproute_test.go +++ b/test/integration/httproute_test.go @@ -18,6 +18,7 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" gatewayclient "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned" "github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" @@ -100,12 +101,12 @@ func TestHTTPRouteEssentials(t *testing.T) { _, err = pluginClient.ConfigurationV1().KongPlugins(ns.Name).Create(ctx, kongplugin, metav1.CreateOptions{}) t.Logf("creating an httproute to access deployment %s via kong", deployment1.Name) - httpPort := gatewayv1alpha2.PortNumber(80) - pathMatchPrefix := gatewayv1alpha2.PathMatchPathPrefix - pathMatchRegularExpression := gatewayv1alpha2.PathMatchRegularExpression - pathMatchExact := gatewayv1alpha2.PathMatchExact - headerMatchRegex := gatewayv1alpha2.HeaderMatchRegularExpression - httpRoute := &gatewayv1alpha2.HTTPRoute{ + httpPort := gatewayv1beta1.PortNumber(80) + pathMatchPrefix := gatewayv1beta1.PathMatchPathPrefix + pathMatchRegularExpression := gatewayv1beta1.PathMatchRegularExpression + pathMatchExact := gatewayv1beta1.PathMatchExact + headerMatchRegex := gatewayv1beta1.HeaderMatchRegularExpression + httpRoute := &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: uuid.NewString(), Annotations: map[string]string{ @@ -113,39 +114,39 @@ func TestHTTPRouteEssentials(t *testing.T) { annotations.AnnotationPrefix + annotations.PluginsKey: "correlation", }, }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Name: gatewayv1alpha2.ObjectName(gateway.Name), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: gatewayv1beta1.ObjectName(gateway.Name), }}, }, - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{ { - Path: &gatewayv1alpha2.HTTPPathMatch{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchPrefix, Value: kong.String("/test-http-route-essentials"), }, }, { - Path: &gatewayv1alpha2.HTTPPathMatch{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchRegularExpression, Value: kong.String(`/regex-\d{3}-test-http-route-essentials`), }, }, { - Path: &gatewayv1alpha2.HTTPPathMatch{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchExact, Value: kong.String(`/exact-test-http-route-essentials`), }, }, }, - BackendRefs: []gatewayv1alpha2.HTTPBackendRef{{ - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName(service1.Name), + BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName(service1.Name), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, }, }}, @@ -153,8 +154,8 @@ func TestHTTPRouteEssentials(t *testing.T) { }, } if util.GetKongVersion().GTE(parser.MinRegexHeaderKongVersion) { - httpRoute.Spec.Rules[0].Matches = append(httpRoute.Spec.Rules[0].Matches, gatewayv1alpha2.HTTPRouteMatch{ - Headers: []gatewayv1alpha2.HTTPHeaderMatch{ + httpRoute.Spec.Rules[0].Matches = append(httpRoute.Spec.Rules[0].Matches, gatewayv1beta1.HTTPRouteMatch{ + Headers: []gatewayv1beta1.HTTPHeaderMatch{ { Type: &headerMatchRegex, Value: "^audio/*", @@ -163,7 +164,7 @@ func TestHTTPRouteEssentials(t *testing.T) { }, }) } - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Create(ctx, httpRoute, metav1.CreateOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Create(ctx, httpRoute, metav1.CreateOptions{}) require.NoError(t, err) cleaner.Add(httpRoute) @@ -206,32 +207,32 @@ func TestHTTPRouteEssentials(t *testing.T) { var httpbinWeight int32 = 75 var nginxWeight int32 = 25 require.Eventually(t, func() bool { - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(httpRoute.Namespace).Get(ctx, httpRoute.Name, metav1.GetOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(httpRoute.Namespace).Get(ctx, httpRoute.Name, metav1.GetOptions{}) require.NoError(t, err) - httpRoute.Spec.Rules[0].BackendRefs = []gatewayv1alpha2.HTTPBackendRef{ + httpRoute.Spec.Rules[0].BackendRefs = []gatewayv1beta1.HTTPBackendRef{ { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName(service1.Name), + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName(service1.Name), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, Weight: &httpbinWeight, }, }, { - BackendRef: gatewayv1alpha2.BackendRef{ - BackendObjectReference: gatewayv1alpha2.BackendObjectReference{ - Name: gatewayv1alpha2.ObjectName(service2.Name), + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: gatewayv1beta1.ObjectName(service2.Name), Port: &httpPort, - Kind: util.StringToGatewayAPIKindPtr("Service"), + Kind: util.StringToGatewayAPIKindV1Beta1Ptr("Service"), }, Weight: &nginxWeight, }, }, } - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(httpRoute.Namespace).Update(ctx, httpRoute, metav1.UpdateOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(httpRoute.Namespace).Update(ctx, httpRoute, metav1.UpdateOptions{}) if err != nil { t.Logf("WARNING: could not update httproute with an additional backendRef: %s (retrying)", err) return false @@ -277,10 +278,10 @@ func TestHTTPRouteEssentials(t *testing.T) { t.Log("removing the parentrefs from the HTTPRoute") oldParentRefs := httpRoute.Spec.ParentRefs require.Eventually(t, func() bool { - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Get(ctx, httpRoute.Name, metav1.GetOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Get(ctx, httpRoute.Name, metav1.GetOptions{}) require.NoError(t, err) httpRoute.Spec.ParentRefs = nil - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Update(ctx, httpRoute, metav1.UpdateOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Update(ctx, httpRoute, metav1.UpdateOptions{}) return err == nil }, time.Minute, time.Second) @@ -293,10 +294,10 @@ func TestHTTPRouteEssentials(t *testing.T) { t.Log("putting the parentRefs back") require.Eventually(t, func() bool { - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Get(ctx, httpRoute.Name, metav1.GetOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Get(ctx, httpRoute.Name, metav1.GetOptions{}) require.NoError(t, err) httpRoute.Spec.ParentRefs = oldParentRefs - httpRoute, err = gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Update(ctx, httpRoute, metav1.UpdateOptions{}) + httpRoute, err = gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Update(ctx, httpRoute, metav1.UpdateOptions{}) return err == nil }, time.Minute, time.Second) diff --git a/test/integration/httproute_webhook_test.go b/test/integration/httproute_webhook_test.go index cfc5ca617b..818e82a3fc 100644 --- a/test/integration/httproute_webhook_test.go +++ b/test/integration/httproute_webhook_test.go @@ -25,7 +25,7 @@ func TestHTTPRouteValidationWebhook(t *testing.T) { t.Skip("webhook tests are only available on KIND clusters currently") } - pathMatchRegex := gatewayv1alpha2.PathMatchRegularExpression + pathMatchRegex := gatewayv1beta1.PathMatchRegularExpression closer, err := ensureAdmissionRegistration( "kong-validations-gateway", @@ -76,21 +76,21 @@ func TestHTTPRouteValidationWebhook(t *testing.T) { for _, tt := range []struct { name string - route *gatewayv1alpha2.HTTPRoute + route *gatewayv1beta1.HTTPRoute wantCreateErr bool wantCreateErrSubstring string }{ { name: "a valid httproute linked to a managed gateway passes validation", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: uuid.NewString(), }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Namespace: (*gatewayv1alpha2.Namespace)(&managedGateway.Namespace), - Name: gatewayv1alpha2.ObjectName(managedGateway.Name), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Namespace: (*gatewayv1beta1.Namespace)(&managedGateway.Namespace), + Name: gatewayv1beta1.ObjectName(managedGateway.Name), }}, }, }, @@ -99,15 +99,15 @@ func TestHTTPRouteValidationWebhook(t *testing.T) { }, { name: "an httproute linked to a non-existent gateway fails validation", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: uuid.NewString(), }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Namespace: (*gatewayv1alpha2.Namespace)(&managedGateway.Namespace), - Name: gatewayv1alpha2.ObjectName("fake-gateway"), + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Namespace: (*gatewayv1beta1.Namespace)(&managedGateway.Namespace), + Name: gatewayv1beta1.ObjectName("fake-gateway"), }}, }, }, @@ -117,22 +117,22 @@ func TestHTTPRouteValidationWebhook(t *testing.T) { }, { name: "an invalid httproute will pass validation if it's not linked to a managed controller (it's not ours)", - route: &gatewayv1alpha2.HTTPRoute{ + route: &gatewayv1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: uuid.NewString(), }, - Spec: gatewayv1alpha2.HTTPRouteSpec{ - Rules: []gatewayv1alpha2.HTTPRouteRule{{ - Matches: []gatewayv1alpha2.HTTPRouteMatch{{ - Path: &gatewayv1alpha2.HTTPPathMatch{ + Spec: gatewayv1beta1.HTTPRouteSpec{ + Rules: []gatewayv1beta1.HTTPRouteRule{{ + Matches: []gatewayv1beta1.HTTPRouteMatch{{ + Path: &gatewayv1beta1.HTTPPathMatch{ Type: &pathMatchRegex, // this route is invalid because we don't support regex path matches (yet) }, }}, }}, - CommonRouteSpec: gatewayv1alpha2.CommonRouteSpec{ - ParentRefs: []gatewayv1alpha2.ParentReference{{ - Namespace: (*gatewayv1alpha2.Namespace)(&unmanagedGateway.Namespace), - Name: gatewayv1alpha2.ObjectName(unmanagedGateway.Name), + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Namespace: (*gatewayv1beta1.Namespace)(&unmanagedGateway.Namespace), + Name: gatewayv1beta1.ObjectName(unmanagedGateway.Name), }}, }, }, @@ -141,7 +141,7 @@ func TestHTTPRouteValidationWebhook(t *testing.T) { }, } { t.Run(tt.name, func(t *testing.T) { - _, err := gatewayClient.GatewayV1alpha2().HTTPRoutes(ns.Name).Create(ctx, tt.route, metav1.CreateOptions{}) + _, err := gatewayClient.GatewayV1beta1().HTTPRoutes(ns.Name).Create(ctx, tt.route, metav1.CreateOptions{}) if tt.wantCreateErr { require.Contains(t, err.Error(), tt.wantCreateErrSubstring) } else {