github.com/cilium/cilium@v1.16.2/operator/pkg/gateway-api/tlsroute.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 "github.com/sirupsen/logrus" 10 corev1 "k8s.io/api/core/v1" 11 "k8s.io/apimachinery/pkg/fields" 12 "k8s.io/apimachinery/pkg/runtime" 13 "k8s.io/apimachinery/pkg/types" 14 ctrl "sigs.k8s.io/controller-runtime" 15 "sigs.k8s.io/controller-runtime/pkg/builder" 16 "sigs.k8s.io/controller-runtime/pkg/client" 17 "sigs.k8s.io/controller-runtime/pkg/handler" 18 "sigs.k8s.io/controller-runtime/pkg/predicate" 19 "sigs.k8s.io/controller-runtime/pkg/reconcile" 20 gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" 21 gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" 22 gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" 23 mcsapiv1alpha1 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" 24 25 "github.com/cilium/cilium/operator/pkg/gateway-api/helpers" 26 "github.com/cilium/cilium/pkg/logging/logfields" 27 ) 28 29 // tlsRouteReconciler reconciles a TLSRoute object 30 type tlsRouteReconciler struct { 31 client.Client 32 Scheme *runtime.Scheme 33 } 34 35 func newTLSRouteReconciler(mgr ctrl.Manager) *tlsRouteReconciler { 36 return &tlsRouteReconciler{ 37 Client: mgr.GetClient(), 38 Scheme: mgr.GetScheme(), 39 } 40 } 41 42 // SetupWithManager sets up the controller with the Manager. 43 func (r *tlsRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { 44 if err := mgr.GetFieldIndexer().IndexField(context.Background(), &gatewayv1alpha2.TLSRoute{}, backendServiceIndex, 45 func(rawObj client.Object) []string { 46 route, ok := rawObj.(*gatewayv1alpha2.TLSRoute) 47 if !ok { 48 return nil 49 } 50 var backendServices []string 51 for _, rule := range route.Spec.Rules { 52 for _, backend := range rule.BackendRefs { 53 namespace := helpers.NamespaceDerefOr(backend.Namespace, route.Namespace) 54 backendServiceName, err := helpers.GetBackendServiceName(r.Client, namespace, backend.BackendObjectReference) 55 if err != nil { 56 log.WithFields(logrus.Fields{ 57 logfields.Controller: "tlsRoute", 58 logfields.Resource: client.ObjectKeyFromObject(rawObj), 59 }).WithError(err).Error("Failed to get backend service name") 60 continue 61 } 62 backendServices = append(backendServices, 63 types.NamespacedName{ 64 Namespace: helpers.NamespaceDerefOr(backend.Namespace, route.Namespace), 65 Name: backendServiceName, 66 }.String(), 67 ) 68 } 69 } 70 return backendServices 71 }, 72 ); err != nil { 73 return err 74 } 75 76 if err := mgr.GetFieldIndexer().IndexField(context.Background(), &gatewayv1alpha2.TLSRoute{}, backendServiceImportIndex, 77 func(rawObj client.Object) []string { 78 hr, ok := rawObj.(*gatewayv1alpha2.TLSRoute) 79 if !ok { 80 return nil 81 } 82 var backendServiceImports []string 83 for _, rule := range hr.Spec.Rules { 84 for _, backend := range rule.BackendRefs { 85 if !helpers.IsServiceImport(backend.BackendObjectReference) { 86 continue 87 } 88 backendServiceImports = append(backendServiceImports, 89 types.NamespacedName{ 90 Namespace: helpers.NamespaceDerefOr(backend.Namespace, hr.Namespace), 91 Name: string(backend.Name), 92 }.String(), 93 ) 94 } 95 } 96 return backendServiceImports 97 }, 98 ); err != nil { 99 return err 100 } 101 102 if err := mgr.GetFieldIndexer().IndexField(context.Background(), &gatewayv1alpha2.TLSRoute{}, gatewayIndex, 103 func(rawObj client.Object) []string { 104 hr := rawObj.(*gatewayv1alpha2.TLSRoute) 105 var gateways []string 106 for _, parent := range hr.Spec.ParentRefs { 107 if !helpers.IsGateway(parent) { 108 continue 109 } 110 gateways = append(gateways, 111 types.NamespacedName{ 112 Namespace: helpers.NamespaceDerefOr(parent.Namespace, hr.Namespace), 113 Name: string(parent.Name), 114 }.String(), 115 ) 116 } 117 return gateways 118 }, 119 ); err != nil { 120 return err 121 } 122 123 builder := ctrl.NewControllerManagedBy(mgr). 124 // Watch for changes to TLSRoute 125 For(&gatewayv1alpha2.TLSRoute{}). 126 // Watch for changes to Backend services 127 Watches(&corev1.Service{}, r.enqueueRequestForBackendService()). 128 // Watch for changes to Reference Grants 129 Watches(&gatewayv1beta1.ReferenceGrant{}, r.enqueueRequestForReferenceGrant()). 130 // Watch for changes to Gateways and enqueue TLSRoutes that reference them 131 Watches(&gatewayv1.Gateway{}, r.enqueueRequestForGateway(), 132 builder.WithPredicates( 133 predicate.NewPredicateFuncs(hasMatchingController(context.Background(), mgr.GetClient(), controllerName)), 134 )) 135 136 if helpers.HasServiceImportSupport(r.Client.Scheme()) { 137 // Watch for changes to Backend Service Imports 138 builder = builder.Watches(&mcsapiv1alpha1.ServiceImport{}, r.enqueueRequestForBackendServiceImport()) 139 } 140 141 return builder.Complete(r) 142 } 143 144 // enqueueRequestForBackendService makes sure that TLS Routes are reconciled 145 // if the backend services are updated. 146 func (r *tlsRouteReconciler) enqueueRequestForBackendService() handler.EventHandler { 147 return handler.EnqueueRequestsFromMapFunc(r.enqueueFromIndex(backendServiceIndex)) 148 } 149 150 // enqueueRequestForBackendServiceImport makes sure that TLS Routes are reconciled 151 // if the backend Service Imports are updated. 152 func (r *tlsRouteReconciler) enqueueRequestForBackendServiceImport() handler.EventHandler { 153 return handler.EnqueueRequestsFromMapFunc(r.enqueueFromIndex(backendServiceImportIndex)) 154 } 155 156 // enqueueRequestForReferenceGrant makes sure that all TLS Routes are reconciled 157 // if a ReferenceGrant changes 158 func (r *tlsRouteReconciler) enqueueRequestForReferenceGrant() handler.EventHandler { 159 return handler.EnqueueRequestsFromMapFunc(r.enqueueAll()) 160 } 161 162 func (r *tlsRouteReconciler) enqueueRequestForGateway() handler.EventHandler { 163 return handler.EnqueueRequestsFromMapFunc(r.enqueueFromIndex(gatewayIndex)) 164 } 165 166 func (r *tlsRouteReconciler) enqueueFromIndex(index string) handler.MapFunc { 167 return func(ctx context.Context, o client.Object) []reconcile.Request { 168 scopedLog := log.WithFields(logrus.Fields{ 169 logfields.Controller: "tlsRoute", 170 logfields.Resource: client.ObjectKeyFromObject(o), 171 }) 172 rList := &gatewayv1alpha2.TLSRouteList{} 173 174 if err := r.Client.List(context.Background(), rList, &client.ListOptions{ 175 FieldSelector: fields.OneTermEqualSelector(index, client.ObjectKeyFromObject(o).String()), 176 }); err != nil { 177 scopedLog.WithError(err).Error("Failed to get related TLSRoutes") 178 return []reconcile.Request{} 179 } 180 181 requests := make([]reconcile.Request, 0, len(rList.Items)) 182 for _, item := range rList.Items { 183 route := client.ObjectKey{ 184 Namespace: item.GetNamespace(), 185 Name: item.GetName(), 186 } 187 requests = append(requests, reconcile.Request{ 188 NamespacedName: route, 189 }) 190 scopedLog.WithField("tlsRoute", route).Info("Enqueued TLSRoute for resource") 191 } 192 return requests 193 } 194 } 195 196 func (r *tlsRouteReconciler) enqueueAll() handler.MapFunc { 197 return func(ctx context.Context, o client.Object) []reconcile.Request { 198 scopedLog := log.WithFields(logrus.Fields{ 199 logfields.Controller: "tlsRoute", 200 logfields.Resource: client.ObjectKeyFromObject(o), 201 }) 202 trList := &gatewayv1alpha2.TLSRouteList{} 203 204 if err := r.Client.List(ctx, trList, &client.ListOptions{}); err != nil { 205 scopedLog.WithError(err).Error("Failed to get TLSRoutes") 206 return []reconcile.Request{} 207 } 208 209 requests := make([]reconcile.Request, 0, len(trList.Items)) 210 for _, item := range trList.Items { 211 route := client.ObjectKey{ 212 Namespace: item.GetNamespace(), 213 Name: item.GetName(), 214 } 215 requests = append(requests, reconcile.Request{ 216 NamespacedName: route, 217 }) 218 scopedLog.WithField("tlsRoute", route).Info("Enqueued TLSRoute for resource") 219 } 220 return requests 221 } 222 }