@@ -223,17 +223,59 @@ func (src *gatewayRouteSource) Endpoints(ctx context.Context) ([]*endpoint.Endpo
223
223
continue
224
224
}
225
225
226
- // Get Route hostnames and their targets.
227
- hostTargets , err := resolver .resolve (rt )
228
- if err != nil {
229
- return nil , err
230
- }
231
- if len (hostTargets ) == 0 {
226
+ // Get Gateway Listeners associated with Route.
227
+ gwListeners := resolver .resolve (rt )
228
+ if len (gwListeners ) == 0 {
232
229
log .Debugf ("No endpoints could be generated from %s %s/%s" , src .rtKind , meta .Namespace , meta .Name )
233
230
continue
234
231
}
235
232
236
- // Create endpoints from hostnames and targets.
233
+ // Create endpoints for Route and associated Gateway Listeners
234
+ rtHosts := rt .Hostnames ()
235
+ if len (rtHosts ) == 0 {
236
+ // This means that the route doesn't specify a hostname and should use any provided by
237
+ // attached Gateway Listeners.
238
+ rtHosts = []v1.Hostname {"" }
239
+ }
240
+
241
+ hostTargets := make (map [string ]endpoint.Targets )
242
+ for gateway , listeners := range gwListeners {
243
+ var hosts []string
244
+ for _ , listener := range listeners {
245
+ // Find all overlapping hostnames between the Route and Listener.
246
+ gwHost := getVal (listener .Hostname , "" )
247
+ for _ , rtHost := range rtHosts {
248
+ host , ok := gwMatchingHost (string (gwHost ), string (rtHost ))
249
+ if ! ok || host == "" {
250
+ continue
251
+ }
252
+ hosts = append (hosts , host )
253
+ }
254
+ }
255
+ // TODO: The ignore-hostname-annotation flag help says "valid only when using fqdn-template"
256
+ // but other sources don't check if fqdn-template is set. Which should it be?
257
+ if ! src .ignoreHostnameAnnotation {
258
+ hosts = append (hosts , getHostnamesFromAnnotations (annots )... )
259
+ }
260
+ // TODO: The combine-fqdn-annotation flag is similarly vague.
261
+ if src .fqdnTemplate != nil && (len (hosts ) == 0 || src .combineFQDNAnnotation ) {
262
+ templated , err := execTemplate (src .fqdnTemplate , rt .Object ())
263
+ if err != nil {
264
+ return nil , err
265
+ }
266
+ hosts = append (hosts , templated ... )
267
+ }
268
+ for _ , host := range hosts {
269
+ override := getTargetsFromTargetAnnotation (gateway .Annotations )
270
+ hostTargets [host ] = append (hostTargets [host ], override ... )
271
+ if len (override ) == 0 {
272
+ for _ , addr := range gateway .Status .Addresses {
273
+ hostTargets [host ] = append (hostTargets [host ], addr .Value )
274
+ }
275
+ }
276
+ }
277
+ }
278
+
237
279
resource := fmt .Sprintf ("%s/%s/%s" , kind , meta .Namespace , meta .Name )
238
280
providerSpecific , setIdentifier := getProviderSpecificAnnotations (annots )
239
281
ttl := getTTLFromAnnotations (annots , resource )
@@ -287,25 +329,21 @@ func newGatewayRouteResolver(src *gatewayRouteSource, gateways []*v1beta1.Gatewa
287
329
}
288
330
}
289
331
290
- func (c * gatewayRouteResolver ) resolve (rt gatewayRoute ) (map [string ]endpoint.Targets , error ) {
291
- rtHosts , err := c .hosts (rt )
292
- if err != nil {
293
- return nil , err
294
- }
295
- hostTargets := make (map [string ]endpoint.Targets )
332
+ func (c * gatewayRouteResolver ) resolve (rt gatewayRoute ) map [* v1beta1.Gateway ][]* v1.Listener {
333
+ gwListeners := map [* v1beta1.Gateway ][]* v1.Listener {}
296
334
297
335
meta := rt .Metadata ()
298
336
for _ , rps := range rt .RouteStatus ().Parents {
299
337
// Confirm the Parent is the standard Gateway kind.
300
338
ref := rps .ParentRef
301
- group := strVal (( * string )( ref .Group ) , gatewayGroup )
302
- kind := strVal (( * string )( ref .Kind ) , gatewayKind )
339
+ group := getVal ( ref .Group , gatewayGroup )
340
+ kind := getVal ( ref .Kind , gatewayKind )
303
341
if group != gatewayGroup || kind != gatewayKind {
304
342
log .Debugf ("Unsupported parent %s/%s for %s %s/%s" , group , kind , c .src .rtKind , meta .Namespace , meta .Name )
305
343
continue
306
344
}
307
345
// Lookup the Gateway and its Listeners.
308
- namespace := strVal ((* string )(ref .Namespace ), meta .Namespace )
346
+ namespace := getVal ((* string )(ref .Namespace ), meta .Namespace )
309
347
gw , ok := c .gws [namespacedName (namespace , string (ref .Name ))]
310
348
if ! ok {
311
349
log .Debugf ("Gateway %s/%s not found for %s %s/%s" , namespace , ref .Name , c .src .rtKind , meta .Namespace , meta .Name )
@@ -318,7 +356,7 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar
318
356
}
319
357
// Match the Route to all possible Listeners.
320
358
match := false
321
- section := sectionVal (ref .SectionName , "" )
359
+ section := getVal (ref .SectionName , "" )
322
360
listeners := gw .listeners [section ]
323
361
for i := range listeners {
324
362
lis := & listeners [i ]
@@ -327,78 +365,35 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar
327
365
continue
328
366
}
329
367
// Confirm that the Listener and Route ports match, if specified.
330
- // EXPERIMENTAL: https://gateway-api.sigs.k8s.io/geps/gep-957/
331
368
if ref .Port != nil && * ref .Port != lis .Port {
332
369
continue
333
370
}
334
371
// Confirm that the Listener allows the Route (based on namespace and kind).
335
372
if ! c .routeIsAllowed (gw .gateway , lis , rt ) {
336
373
continue
337
374
}
338
- // Find all overlapping hostnames between the Route and Listener.
339
- // For {TCP,UDP}Routes, all annotation-generated hostnames should match since the Listener doesn't specify a hostname.
340
- // For {HTTP,TLS}Routes, hostnames (including any annotation-generated) will be required to match any Listeners specified hostname.
341
- gwHost := ""
342
- if lis .Hostname != nil {
343
- gwHost = string (* lis .Hostname )
344
- }
345
- for _ , rtHost := range rtHosts {
346
- if gwHost == "" && rtHost == "" {
347
- // For {HTTP,TLS}Routes, this means the Route and the Listener both allow _any_ hostnames.
348
- // For {TCP,UDP}Routes, this should always happen since neither specifies hostnames.
349
- continue
350
- }
351
- host , ok := gwMatchingHost (gwHost , rtHost )
352
- if ! ok {
353
- continue
354
- }
355
- override := getTargetsFromTargetAnnotation (gw .gateway .Annotations )
356
- hostTargets [host ] = append (hostTargets [host ], override ... )
357
- if len (override ) == 0 {
358
- for _ , addr := range gw .gateway .Status .Addresses {
359
- hostTargets [host ] = append (hostTargets [host ], addr .Value )
375
+ // Confirm that the Listener and Route hostnames overlap, if specified.
376
+ overlap := true
377
+ if len (rt .Hostnames ()) != 0 {
378
+ gwHost := getVal (lis .Hostname , "" )
379
+ for _ , rtHost := range rt .Hostnames () {
380
+ _ , overlap = gwMatchingHost (string (gwHost ), string (rtHost ))
381
+ if overlap {
382
+ break
360
383
}
361
384
}
362
- match = true
363
385
}
386
+ if ! overlap {
387
+ continue
388
+ }
389
+ gwListeners [gw .gateway ] = append (gwListeners [gw .gateway ], lis )
390
+ match = true
364
391
}
365
392
if ! match {
366
- log .Debugf ("Gateway %s/%s section %q does not match %s %s/%s hostnames %q" , namespace , ref .Name , section , c .src .rtKind , meta .Namespace , meta .Name , rtHosts )
393
+ log .Debugf ("Gateway %s/%s section %q does not match %s %s/%s hostnames %q" , namespace , ref .Name , section , c .src .rtKind , meta .Namespace , meta .Name , rt . Hostnames () )
367
394
}
368
395
}
369
- // If a Gateway has multiple matching Listeners for the same host, then we'll
370
- // add its IPs to the target list multiple times and should dedupe them.
371
- for host , targets := range hostTargets {
372
- hostTargets [host ] = uniqueTargets (targets )
373
- }
374
- return hostTargets , nil
375
- }
376
-
377
- func (c * gatewayRouteResolver ) hosts (rt gatewayRoute ) ([]string , error ) {
378
- var hostnames []string
379
- for _ , name := range rt .Hostnames () {
380
- hostnames = append (hostnames , string (name ))
381
- }
382
- // TODO: The ignore-hostname-annotation flag help says "valid only when using fqdn-template"
383
- // but other sources don't check if fqdn-template is set. Which should it be?
384
- if ! c .src .ignoreHostnameAnnotation {
385
- hostnames = append (hostnames , getHostnamesFromAnnotations (rt .Metadata ().Annotations )... )
386
- }
387
- // TODO: The combine-fqdn-annotation flag is similarly vague.
388
- if c .src .fqdnTemplate != nil && (len (hostnames ) == 0 || c .src .combineFQDNAnnotation ) {
389
- hosts , err := execTemplate (c .src .fqdnTemplate , rt .Object ())
390
- if err != nil {
391
- return nil , err
392
- }
393
- hostnames = append (hostnames , hosts ... )
394
- }
395
- // This means that the route doesn't specify a hostname and should use any provided by
396
- // attached Gateway Listeners. This is only useful for {HTTP,TLS}Routes, but it doesn't
397
- // break {TCP,UDP}Routes.
398
- if len (rt .Hostnames ()) == 0 {
399
- hostnames = append (hostnames , "" )
400
- }
401
- return hostnames , nil
396
+ return gwListeners
402
397
}
403
398
404
399
func (c * gatewayRouteResolver ) routeIsAllowed (gw * v1beta1.Gateway , lis * v1.Listener , rt gatewayRoute ) bool {
@@ -445,7 +440,7 @@ func (c *gatewayRouteResolver) routeIsAllowed(gw *v1beta1.Gateway, lis *v1.Liste
445
440
}
446
441
gvk := rt .Object ().GetObjectKind ().GroupVersionKind ()
447
442
for _ , gk := range allow .Kinds {
448
- group := strVal (( * string )( gk .Group ) , gatewayGroup )
443
+ group := string ( getVal ( gk .Group , gatewayGroup ) )
449
444
if gvk .Group == group && gvk .Kind == string (gk .Kind ) {
450
445
return true
451
446
}
@@ -462,24 +457,6 @@ func gwRouteIsAccepted(conds []metav1.Condition) bool {
462
457
return false
463
458
}
464
459
465
- func uniqueTargets (targets endpoint.Targets ) endpoint.Targets {
466
- if len (targets ) < 2 {
467
- return targets
468
- }
469
- sort .Strings ([]string (targets ))
470
- prev := targets [0 ]
471
- n := 1
472
- for _ , v := range targets [1 :] {
473
- if v == prev {
474
- continue
475
- }
476
- prev = v
477
- targets [n ] = v
478
- n ++
479
- }
480
- return targets [:n ]
481
- }
482
-
483
460
// gwProtocolMatches returns whether a and b are the same protocol,
484
461
// where HTTP and HTTPS are considered the same.
485
462
// and TLS and TCP are considered the same.
@@ -583,16 +560,9 @@ func isAlphaNum(b byte) bool {
583
560
}
584
561
}
585
562
586
- func strVal (ptr * string , def string ) string {
587
- if ptr == nil || * ptr == "" {
588
- return def
589
- }
590
- return * ptr
591
- }
592
-
593
- func sectionVal (ptr * v1.SectionName , def v1.SectionName ) v1.SectionName {
594
- if ptr == nil || * ptr == "" {
595
- return def
563
+ func getVal [T any ](ptr * T , def T ) T {
564
+ if ptr == nil {
565
+ return T (def )
596
566
}
597
567
return * ptr
598
568
}
0 commit comments