github.com/cilium/cilium@v1.16.2/operator/pkg/gateway-api/routechecks/grpcroute.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  	gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
    20  
    21  	"github.com/cilium/cilium/operator/pkg/gateway-api/helpers"
    22  )
    23  
    24  var _ Input = (*GRPCRouteInput)(nil)
    25  
    26  // GRPCRouteInput is used to implement the Input interface for GRPCRoute
    27  type GRPCRouteInput struct {
    28  	Ctx       context.Context
    29  	Logger    *logrus.Entry
    30  	Client    client.Client
    31  	Grants    *gatewayv1beta1.ReferenceGrantList
    32  	GRPCRoute *gatewayv1.GRPCRoute
    33  
    34  	gateways map[gatewayv1.ParentReference]*gatewayv1.Gateway
    35  }
    36  
    37  // GRPCRouteRule is used to implement the GenericRule interface for GRPCRoute
    38  type GRPCRouteRule struct {
    39  	Rule gatewayv1.GRPCRouteRule
    40  }
    41  
    42  func (g *GRPCRouteRule) GetBackendRefs() []gatewayv1.BackendRef {
    43  	var refs []gatewayv1.BackendRef
    44  	for _, b := range g.Rule.BackendRefs {
    45  		refs = append(refs, b.BackendRef)
    46  	}
    47  
    48  	for _, f := range g.Rule.Filters {
    49  		if f.Type == gatewayv1.GRPCRouteFilterRequestMirror {
    50  			if f.RequestMirror == nil {
    51  				continue
    52  			}
    53  			refs = append(refs, gatewayv1.BackendRef{
    54  				BackendObjectReference: f.RequestMirror.BackendRef,
    55  			})
    56  		}
    57  	}
    58  
    59  	return refs
    60  }
    61  
    62  func (g *GRPCRouteInput) GetRules() []GenericRule {
    63  	var rules []GenericRule
    64  	for _, rule := range g.GRPCRoute.Spec.Rules {
    65  		rules = append(rules, &GRPCRouteRule{rule})
    66  	}
    67  	return rules
    68  }
    69  
    70  func (g *GRPCRouteInput) GetNamespace() string {
    71  	return g.GRPCRoute.GetNamespace()
    72  }
    73  
    74  func (g *GRPCRouteInput) GetClient() client.Client {
    75  	return g.Client
    76  }
    77  
    78  func (g *GRPCRouteInput) GetContext() context.Context {
    79  	return g.Ctx
    80  }
    81  
    82  func (g *GRPCRouteInput) GetGVK() schema.GroupVersionKind {
    83  	return gatewayv1.SchemeGroupVersion.WithKind("GRPCRoute")
    84  }
    85  
    86  func (g *GRPCRouteInput) GetGrants() []gatewayv1beta1.ReferenceGrant {
    87  	return g.Grants.Items
    88  }
    89  
    90  func (g *GRPCRouteInput) GetGateway(parent gatewayv1.ParentReference) (*gatewayv1.Gateway, error) {
    91  	if g.gateways == nil {
    92  		g.gateways = make(map[gatewayv1.ParentReference]*gatewayv1.Gateway)
    93  	}
    94  
    95  	if gw, exists := g.gateways[parent]; exists {
    96  		return gw, nil
    97  	}
    98  
    99  	ns := helpers.NamespaceDerefOr(parent.Namespace, g.GetNamespace())
   100  	gw := &gatewayv1.Gateway{}
   101  
   102  	if err := g.Client.Get(g.Ctx, client.ObjectKey{Namespace: ns, Name: string(parent.Name)}, gw); err != nil {
   103  		if !k8serrors.IsNotFound(err) {
   104  			// if it is not just a not found error, we should return the error as something is bad
   105  			return nil, fmt.Errorf("error while getting gateway: %w", err)
   106  		}
   107  
   108  		// Gateway does not exist skip further checks
   109  		return nil, fmt.Errorf("gateway %q does not exist: %w", parent.Name, err)
   110  	}
   111  
   112  	g.gateways[parent] = gw
   113  	return gw, nil
   114  }
   115  
   116  func (g *GRPCRouteInput) GetParentGammaService(parent gatewayv1.ParentReference) (*corev1.Service, error) {
   117  	return nil, fmt.Errorf("GAMMA support is not implemented in this reconciler")
   118  }
   119  
   120  func (g *GRPCRouteInput) GetHostnames() []gatewayv1beta1.Hostname {
   121  	return g.GRPCRoute.Spec.Hostnames
   122  }
   123  
   124  func (g *GRPCRouteInput) SetParentCondition(ref gatewayv1beta1.ParentReference, condition metav1.Condition) {
   125  	condition.LastTransitionTime = metav1.NewTime(time.Now())
   126  	condition.ObservedGeneration = g.GRPCRoute.GetGeneration()
   127  
   128  	g.mergeStatusConditions(ref, []metav1.Condition{
   129  		condition,
   130  	})
   131  }
   132  
   133  func (g *GRPCRouteInput) SetAllParentCondition(condition metav1.Condition) {
   134  	// fill in the condition
   135  	condition.LastTransitionTime = metav1.NewTime(time.Now())
   136  	condition.ObservedGeneration = g.GRPCRoute.GetGeneration()
   137  
   138  	for _, parent := range g.GRPCRoute.Spec.ParentRefs {
   139  		g.mergeStatusConditions(parent, []metav1.Condition{
   140  			condition,
   141  		})
   142  	}
   143  }
   144  
   145  func (g *GRPCRouteInput) Log() *logrus.Entry {
   146  	return g.Logger
   147  }
   148  
   149  func (g *GRPCRouteInput) mergeStatusConditions(parentRef gatewayv1.ParentReference, updates []metav1.Condition) {
   150  	index := -1
   151  	for i, parent := range g.GRPCRoute.Status.RouteStatus.Parents {
   152  		if reflect.DeepEqual(parent.ParentRef, parentRef) {
   153  			index = i
   154  			break
   155  		}
   156  	}
   157  	if index != -1 {
   158  		g.GRPCRoute.Status.RouteStatus.Parents[index].Conditions = merge(g.GRPCRoute.Status.RouteStatus.Parents[index].Conditions, updates...)
   159  		return
   160  	}
   161  	g.GRPCRoute.Status.RouteStatus.Parents = append(g.GRPCRoute.Status.RouteStatus.Parents, gatewayv1.RouteParentStatus{
   162  		ParentRef:      parentRef,
   163  		ControllerName: controllerName,
   164  		Conditions:     updates,
   165  	})
   166  }