github.com/cilium/cilium@v1.16.2/operator/pkg/gateway-api/routechecks/httproute.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package routechecks 5 6 import ( 7 "context" 8 "fmt" 9 "reflect" 10 "time" 11 12 "github.com/sirupsen/logrus" 13 corev1 "k8s.io/api/core/v1" 14 k8serrors "k8s.io/apimachinery/pkg/api/errors" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/runtime/schema" 17 "sigs.k8s.io/controller-runtime/pkg/client" 18 gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" 19 gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" 20 gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" 21 22 "github.com/cilium/cilium/operator/pkg/gateway-api/helpers" 23 ) 24 25 // HTTPRouteInput is used to implement the Input interface for HTTPRoute 26 type HTTPRouteInput struct { 27 Ctx context.Context 28 Logger *logrus.Entry 29 Client client.Client 30 Grants *gatewayv1beta1.ReferenceGrantList 31 HTTPRoute *gatewayv1.HTTPRoute 32 33 gateways map[gatewayv1.ParentReference]*gatewayv1.Gateway 34 gammaServices map[gatewayv1.ParentReference]*corev1.Service 35 } 36 37 func (h *HTTPRouteInput) SetParentCondition(ref gatewayv1.ParentReference, condition metav1.Condition) { 38 // fill in the condition 39 condition.LastTransitionTime = metav1.NewTime(time.Now()) 40 condition.ObservedGeneration = h.HTTPRoute.GetGeneration() 41 42 h.mergeStatusConditions(ref, []metav1.Condition{ 43 condition, 44 }) 45 } 46 47 func (h *HTTPRouteInput) SetAllParentCondition(condition metav1.Condition) { 48 // fill in the condition 49 condition.LastTransitionTime = metav1.NewTime(time.Now()) 50 condition.ObservedGeneration = h.HTTPRoute.GetGeneration() 51 52 for _, parent := range h.HTTPRoute.Spec.ParentRefs { 53 h.mergeStatusConditions(parent, []metav1.Condition{ 54 condition, 55 }) 56 } 57 } 58 59 func (h *HTTPRouteInput) mergeStatusConditions(parentRef gatewayv1alpha2.ParentReference, updates []metav1.Condition) { 60 index := -1 61 for i, parent := range h.HTTPRoute.Status.RouteStatus.Parents { 62 if reflect.DeepEqual(parent.ParentRef, parentRef) { 63 index = i 64 break 65 } 66 } 67 if index != -1 { 68 h.HTTPRoute.Status.RouteStatus.Parents[index].Conditions = merge(h.HTTPRoute.Status.RouteStatus.Parents[index].Conditions, updates...) 69 return 70 } 71 h.HTTPRoute.Status.RouteStatus.Parents = append(h.HTTPRoute.Status.RouteStatus.Parents, gatewayv1alpha2.RouteParentStatus{ 72 ParentRef: parentRef, 73 ControllerName: controllerName, 74 Conditions: updates, 75 }) 76 } 77 78 func (h *HTTPRouteInput) GetGrants() []gatewayv1beta1.ReferenceGrant { 79 return h.Grants.Items 80 } 81 82 func (h *HTTPRouteInput) GetNamespace() string { 83 return h.HTTPRoute.GetNamespace() 84 } 85 86 func (h *HTTPRouteInput) GetGVK() schema.GroupVersionKind { 87 return gatewayv1.SchemeGroupVersion.WithKind("HTTPRoute") 88 } 89 90 func (h *HTTPRouteInput) GetRules() []GenericRule { 91 var rules []GenericRule 92 for _, rule := range h.HTTPRoute.Spec.Rules { 93 rules = append(rules, &HTTPRouteRule{rule}) 94 } 95 return rules 96 } 97 98 func (h *HTTPRouteInput) GetClient() client.Client { 99 return h.Client 100 } 101 102 func (h *HTTPRouteInput) GetContext() context.Context { 103 return h.Ctx 104 } 105 106 func (h *HTTPRouteInput) GetHostnames() []gatewayv1.Hostname { 107 return h.HTTPRoute.Spec.Hostnames 108 } 109 110 func (h *HTTPRouteInput) GetGateway(parent gatewayv1.ParentReference) (*gatewayv1.Gateway, error) { 111 if h.gateways == nil { 112 h.gateways = make(map[gatewayv1.ParentReference]*gatewayv1.Gateway) 113 } 114 115 if gw, exists := h.gateways[parent]; exists { 116 return gw, nil 117 } 118 119 ns := helpers.NamespaceDerefOr(parent.Namespace, h.GetNamespace()) 120 gw := &gatewayv1.Gateway{} 121 122 if err := h.Client.Get(h.Ctx, client.ObjectKey{Namespace: ns, Name: string(parent.Name)}, gw); err != nil { 123 if !k8serrors.IsNotFound(err) { 124 // if it is not just a not found error, we should return the error as something is bad 125 return nil, fmt.Errorf("error while getting gateway: %w", err) 126 } 127 128 // Gateway does not exist skip further checks 129 return nil, fmt.Errorf("gateway %q does not exist: %w", parent.Name, err) 130 } 131 132 h.gateways[parent] = gw 133 134 return gw, nil 135 } 136 137 func (h *HTTPRouteInput) GetParentGammaService(parent gatewayv1.ParentReference) (*corev1.Service, error) { 138 if h.gammaServices == nil { 139 h.gammaServices = make(map[gatewayv1.ParentReference]*corev1.Service) 140 } 141 142 if s, exists := h.gammaServices[parent]; exists { 143 return s, nil 144 } 145 146 ns := helpers.NamespaceDerefOr(parent.Namespace, h.GetNamespace()) 147 s := &corev1.Service{} 148 149 if err := h.Client.Get(h.Ctx, client.ObjectKey{Namespace: ns, Name: string(parent.Name)}, s); err != nil { 150 if !k8serrors.IsNotFound(err) { 151 // if it is not just a not found error, we should return the error as something is bad 152 return nil, fmt.Errorf("error while getting gateway: %w", err) 153 } 154 155 // Gateway does not exist skip further checks 156 return nil, fmt.Errorf("service %q does not exist: %w", parent.Name, err) 157 } 158 159 h.gammaServices[parent] = s 160 161 return s, nil 162 } 163 164 func (h *HTTPRouteInput) Log() *logrus.Entry { 165 return h.Logger 166 } 167 168 // HTTPRouteRule is used to implement the GenericRule interface for TLSRoute 169 type HTTPRouteRule struct { 170 Rule gatewayv1.HTTPRouteRule 171 } 172 173 func (t *HTTPRouteRule) GetBackendRefs() []gatewayv1.BackendRef { 174 var refs []gatewayv1.BackendRef 175 for _, backend := range t.Rule.BackendRefs { 176 refs = append(refs, backend.BackendRef) 177 } 178 for _, f := range t.Rule.Filters { 179 if f.Type == gatewayv1.HTTPRouteFilterRequestMirror { 180 if f.RequestMirror == nil { 181 continue 182 } 183 refs = append(refs, gatewayv1.BackendRef{ 184 BackendObjectReference: f.RequestMirror.BackendRef, 185 }) 186 } 187 } 188 return refs 189 }