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 }