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  }