github.com/cilium/cilium@v1.16.2/operator/pkg/gateway-api/helpers.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package gateway_api
     5  
     6  import (
     7  	"context"
     8  
     9  	corev1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"sigs.k8s.io/controller-runtime/pkg/client"
    12  	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
    13  	gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
    14  
    15  	"github.com/cilium/cilium/operator/pkg/model"
    16  )
    17  
    18  const (
    19  	kindGateway   = "Gateway"
    20  	kindHTTPRoute = "HTTPRoute"
    21  	kindTLSRoute  = "TLSRoute"
    22  	kindUDPRoute  = "UDPRoute"
    23  	kindTCPRoute  = "TCPRoute"
    24  	kindService   = "Service"
    25  	kindSecret    = "Secret"
    26  )
    27  
    28  func GatewayAddressTypePtr(addr gatewayv1.AddressType) *gatewayv1.AddressType {
    29  	return &addr
    30  }
    31  
    32  func GroupPtr(name string) *gatewayv1.Group {
    33  	group := gatewayv1.Group(name)
    34  	return &group
    35  }
    36  
    37  func KindPtr(name string) *gatewayv1.Kind {
    38  	kind := gatewayv1.Kind(name)
    39  	return &kind
    40  }
    41  
    42  func ObjectNamePtr(name string) *gatewayv1.ObjectName {
    43  	objectName := gatewayv1.ObjectName(name)
    44  	return &objectName
    45  }
    46  
    47  func groupDerefOr(group *gatewayv1.Group, defaultGroup string) string {
    48  	if group != nil && *group != "" {
    49  		return string(*group)
    50  	}
    51  	return defaultGroup
    52  }
    53  
    54  // isAllowed returns true if the provided Route is allowed to attach to given gateway
    55  func isAllowed(ctx context.Context, c client.Client, gw *gatewayv1.Gateway, route metav1.Object) bool {
    56  	for _, listener := range gw.Spec.Listeners {
    57  		// all routes in the same namespace are allowed for this listener
    58  		if listener.AllowedRoutes == nil || listener.AllowedRoutes.Namespaces == nil {
    59  			return route.GetNamespace() == gw.GetNamespace()
    60  		}
    61  
    62  		// check if route is kind-allowed
    63  		if !isKindAllowed(listener, route) {
    64  			continue
    65  		}
    66  
    67  		// check if route is namespace-allowed
    68  		switch *listener.AllowedRoutes.Namespaces.From {
    69  		case gatewayv1.NamespacesFromAll:
    70  			return true
    71  		case gatewayv1.NamespacesFromSame:
    72  			if route.GetNamespace() == gw.GetNamespace() {
    73  				return true
    74  			}
    75  		case gatewayv1.NamespacesFromSelector:
    76  			nsList := &corev1.NamespaceList{}
    77  			selector, _ := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector)
    78  			if err := c.List(ctx, nsList, client.MatchingLabelsSelector{Selector: selector}); err != nil {
    79  				log.WithError(err).Error("Unable to list namespaces")
    80  				return false
    81  			}
    82  
    83  			for _, ns := range nsList.Items {
    84  				if ns.Name == route.GetNamespace() {
    85  					return true
    86  				}
    87  			}
    88  		}
    89  	}
    90  	return false
    91  }
    92  
    93  func isKindAllowed(listener gatewayv1.Listener, route metav1.Object) bool {
    94  	if listener.AllowedRoutes.Kinds == nil {
    95  		return true
    96  	}
    97  
    98  	routeKind := getGatewayKindForObject(route)
    99  
   100  	for _, kind := range listener.AllowedRoutes.Kinds {
   101  		if (kind.Group == nil || string(*kind.Group) == gatewayv1.GroupName) &&
   102  			kind.Kind == kindHTTPRoute && routeKind == kindHTTPRoute {
   103  			return true
   104  		} else if (kind.Group == nil || string(*kind.Group) == gatewayv1alpha2.GroupName) &&
   105  			kind.Kind == kindTLSRoute && routeKind == kindTLSRoute {
   106  			return true
   107  		}
   108  	}
   109  	return false
   110  }
   111  
   112  func computeHosts[T ~string](gw *gatewayv1.Gateway, hostnames []T, excludeHostNames []T) []string {
   113  	hosts := make([]string, 0, len(hostnames))
   114  	for _, listener := range gw.Spec.Listeners {
   115  		hosts = append(hosts, computeHostsForListener(&listener, hostnames, excludeHostNames)...)
   116  	}
   117  
   118  	return hosts
   119  }
   120  
   121  func computeHostsForListener[T ~string](listener *gatewayv1.Listener, hostnames []T, excludeHostNames []T) []string {
   122  	return model.ComputeHosts(toStringSlice(hostnames), (*string)(listener.Hostname), toStringSlice(excludeHostNames))
   123  }
   124  
   125  func toStringSlice[T ~string](s []T) []string {
   126  	res := make([]string, 0, len(s))
   127  	for _, h := range s {
   128  		res = append(res, string(h))
   129  	}
   130  	return res
   131  }
   132  
   133  func getSupportedGroupKind(protocol gatewayv1.ProtocolType) (*gatewayv1.Group, gatewayv1.Kind) {
   134  	switch protocol {
   135  	case gatewayv1.TLSProtocolType:
   136  		return GroupPtr(gatewayv1alpha2.GroupName), kindTLSRoute
   137  	case gatewayv1.HTTPSProtocolType:
   138  		return GroupPtr(gatewayv1.GroupName), kindHTTPRoute
   139  	case gatewayv1.HTTPProtocolType:
   140  		return GroupPtr(gatewayv1.GroupName), kindHTTPRoute
   141  	case gatewayv1.TCPProtocolType:
   142  		return GroupPtr(gatewayv1alpha2.GroupName), kindTCPRoute
   143  	case gatewayv1.UDPProtocolType:
   144  		return GroupPtr(gatewayv1alpha2.GroupName), kindUDPRoute
   145  	default:
   146  		return GroupPtr("Unknown"), "Unknown"
   147  	}
   148  }
   149  func getGatewayKindForObject(obj metav1.Object) gatewayv1.Kind {
   150  	switch obj.(type) {
   151  	case *gatewayv1.HTTPRoute:
   152  		return kindHTTPRoute
   153  	case *gatewayv1alpha2.TLSRoute:
   154  		return kindTLSRoute
   155  	case *gatewayv1alpha2.UDPRoute:
   156  		return kindUDPRoute
   157  	case *gatewayv1alpha2.TCPRoute:
   158  		return kindTCPRoute
   159  	default:
   160  		return "Unknown"
   161  	}
   162  }
   163  
   164  func mergeMap(left, right map[string]string) map[string]string {
   165  	if left == nil {
   166  		return right
   167  	} else {
   168  		for key, value := range right {
   169  			left[key] = value
   170  		}
   171  	}
   172  	return left
   173  }
   174  
   175  func setMergedLabelsAndAnnotations(temp, desired client.Object) {
   176  	temp.SetAnnotations(mergeMap(temp.GetAnnotations(), desired.GetAnnotations()))
   177  	temp.SetLabels(mergeMap(temp.GetLabels(), desired.GetLabels()))
   178  }