Skip to content

Commit

Permalink
chore(refactor): streamline logic for HTTPRoute translation and valid…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
programmer04 committed Dec 16, 2024
1 parent 965a7f4 commit 9443c17
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 90 deletions.
32 changes: 30 additions & 2 deletions internal/admission/validation/gateway/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import (
"strings"

"github.com/kong/go-kong/kong"
"github.com/samber/lo"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kong/kubernetes-ingress-controller/v3/internal/admission/validation"
gatewaycontroller "github.com/kong/kubernetes-ingress-controller/v3/internal/controllers/gateway"
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/kongstate"
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/translator"
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/translator/subtranslator"
"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
)

type routeValidator interface {
Expand Down Expand Up @@ -190,15 +193,40 @@ func validateWithKongGateway(
// Use KIC translator that works both for traditional and expressions based routes.
var kongRoutes []kong.Route
var errMsgs []string
// Gather the K8s object information and hostnames from the HTTPRoute.
objectInfo := util.FromK8sObject(httproute)
hostnames := lo.Map(httproute.Spec.Hostnames, func(h gatewayapi.Hostname, _ int) string {
return string(h)
})
for _, rule := range httproute.Spec.Rules {
translation := subtranslator.KongRouteTranslation{
Name: "validation-attempt",
Matches: rule.Matches,
Filters: rule.Filters,
}
routes, err := translator.GenerateKongRouteFromTranslation(
httproute, translation, translatorFeatures.ExpressionRoutes,

var (
routes []kongstate.Route
err error
)
tags := util.GenerateTagsForObject(httproute, util.AdditionalTagsK8sNamedRouteRule(translation.OptionalNamedRouteRules...)...)
if translatorFeatures.ExpressionRoutes {
routes, err = subtranslator.GenerateKongExpressionRoutesFromTranslation(
translation,
objectInfo,
hostnames,
tags,
)
} else {
routes, err = subtranslator.GenerateKongRoutesFromHTTPRouteMatches(
translation.Name,
translation.Matches,
translation.Filters,
objectInfo,
lo.ToSlicePtr(hostnames),
tags,
)
}
if err != nil {
errMsgs = append(errMsgs, err.Error())
continue
Expand Down
57 changes: 18 additions & 39 deletions internal/dataplane/translator/subtranslator/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,29 +702,28 @@ func GenerateKongRoutesFromHTTPRouteMatches(
hostnames []*string,
tags []*string,
) ([]kongstate.Route, error) {
r := kongstate.Route{
Ingress: ingressObjectInfo,
Route: kong.Route{
Name: kong.String(routeName),
Protocols: kong.StringSlice("http", "https"),
PreserveHost: kong.Bool(true),
Tags: tags,
},
}
// Attach any hostnames associated with the HTTPRoute.
if len(hostnames) > 0 {
r.Hosts = hostnames
}
// It's acceptable for an HTTPRoute to have no matches in the rulesets,
// but only backends as long as there are hostnames. In this case, we
// match all traffic based on the hostname and leave all other routing
// options default.
// For rules with no hostnames, we generate a "catch-all" route for it.
if len(matches) == 0 {
// it's acceptable for an HTTPRoute to have no matches in the rulesets,
// but only backends as long as there are hostnames. In this case, we
// match all traffic based on the hostname and leave all other routing
// options default.
// for rules with no hostnames, we generate a "catch-all" route for it.
r := kongstate.Route{
Ingress: ingressObjectInfo,
Route: kong.Route{
Name: kong.String(routeName),
Protocols: kong.StringSlice("http", "https"),
PreserveHost: kong.Bool(true),
Tags: tags,
},
}
r.Hosts = append(r.Hosts, hostnames...)

return []kongstate.Route{r}, nil
}

r := generateKongstateHTTPRoute(routeName, ingressObjectInfo, hostnames)
r.Tags = tags

// convert header matching from HTTPRoute to Route format
headers, err := convertGatewayMatchHeadersToKongRouteMatchHeaders(matches[0].Headers)
if err != nil {
Expand Down Expand Up @@ -775,26 +774,6 @@ func GenerateKongRoutesFromHTTPRouteMatches(
return routes, nil
}

func generateKongstateHTTPRoute(routeName string, ingressObjectInfo util.K8sObjectInfo, hostnames []*string) kongstate.Route {
// build the route object using the method and pathing information
r := kongstate.Route{
Ingress: ingressObjectInfo,
Route: kong.Route{
Name: kong.String(routeName),
Protocols: kong.StringSlice("http", "https"),
PreserveHost: kong.Bool(true),
// metadata tags aren't added here, they're added by the caller
},
}

// attach any hostnames associated with the httproute
if len(hostnames) > 0 {
r.Hosts = hostnames
}

return r
}

// 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 []gatewayapi.HTTPHeaderMatch) (map[string][]string, error) {
Expand Down
6 changes: 4 additions & 2 deletions internal/dataplane/translator/subtranslator/httproute_atc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import (
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
)

// GenerateKongExpressionRoutesFromHTTPRouteMatches generates Kong routes from HTTPRouteRule
// GenerateKongExpressionRoutesFromTranslation generates Kong routes from HTTPRouteRule
// pointing to a specific backend.
func GenerateKongExpressionRoutesFromHTTPRouteMatches(
// NOTICE: currently it's used only for validation in internal/admission/validation/gateway/httproute.go file,
// for generation of actual config sent to Kong Gateway see translateHTTPRouteRulesMetaToKongstateService function.
func GenerateKongExpressionRoutesFromTranslation(
translation KongRouteTranslation,
ingressObjectInfo util.K8sObjectInfo,
hostnames []string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func TestGenerateKongExpressionRoutesFromHTTPRouteMatches(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
routes, err := GenerateKongExpressionRoutesFromHTTPRouteMatches(
routes, err := GenerateKongExpressionRoutesFromTranslation(
KongRouteTranslation{
Name: tc.routeName,
Matches: tc.matches,
Expand Down
46 changes: 0 additions & 46 deletions internal/dataplane/translator/translate_httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import (
"github.com/samber/lo"
k8stypes "k8s.io/apimachinery/pkg/types"

"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/kongstate"
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/translator/subtranslator"
"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
)

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -110,15 +108,6 @@ func (t *Translator) ingressRulesFromHTTPRoutesWithCombinedService(httpRoutes []
// Translate HTTPRoute - Utils
// -----------------------------------------------------------------------------

// getHTTPRouteHostnamesAsSliceOfStrings translates the hostnames defined in an
// HTTPRoute specification into a []*string slice, which is the type required by translating to matchers
// in expression based routes.
func getHTTPRouteHostnamesAsSliceOfStrings(httproute *gatewayapi.HTTPRoute) []string {
return lo.Map(httproute.Spec.Hostnames, func(h gatewayapi.Hostname, _ int) string {
return string(h)
})
}

// getHTTPRouteHostnamesAsSliceOfStringPointers translates the hostnames defined
// in an HTTPRoute specification into a []*string slice, which is the type required
// by kong.Route{}.
Expand All @@ -127,38 +116,3 @@ func getHTTPRouteHostnamesAsSliceOfStringPointers(httproute *gatewayapi.HTTPRout
return kong.String(string(h))
})
}

// GenerateKongRouteFromTranslation generates Kong routes from HTTPRoute
// pointing to a specific backend. It is used for both traditional and expression based routes.
func GenerateKongRouteFromTranslation(
httproute *gatewayapi.HTTPRoute,
translation subtranslator.KongRouteTranslation,
expressionRoutes bool,
) ([]kongstate.Route, error) {
// Gather the k8s object information and hostnames from the HTTPRoute.
objectInfo := util.FromK8sObject(httproute)
tags := util.GenerateTagsForObject(httproute, util.AdditionalTagsK8sNamedRouteRule(translation.OptionalNamedRouteRules...)...)

// translate to expression based routes when expressionRoutes is enabled.
if expressionRoutes {
// get the hostnames from the HTTPRoute
hostnames := getHTTPRouteHostnamesAsSliceOfStrings(httproute)
return subtranslator.GenerateKongExpressionRoutesFromHTTPRouteMatches(
translation,
objectInfo,
hostnames,
tags,
)
}

// get the hostnames from the HTTPRoute
hostnames := getHTTPRouteHostnamesAsSliceOfStringPointers(httproute)
return subtranslator.GenerateKongRoutesFromHTTPRouteMatches(
translation.Name,
translation.Matches,
translation.Filters,
objectInfo,
hostnames,
tags,
)
}

0 comments on commit 9443c17

Please sign in to comment.