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 }