11package graph
22
33import (
4+ "fmt"
5+
6+ v1 "k8s.io/api/core/v1"
47 "k8s.io/apimachinery/pkg/types"
58 "sigs.k8s.io/controller-runtime/pkg/client"
69 inference "sigs.k8s.io/gateway-api-inference-extension/api/v1"
10+ apiv1 "sigs.k8s.io/gateway-api/apis/v1"
711
12+ "github.com/nginx/nginx-gateway-fabric/v2/internal/controller/state/conditions"
813 "github.com/nginx/nginx-gateway-fabric/v2/internal/framework/controller"
914 "github.com/nginx/nginx-gateway-fabric/v2/internal/framework/kinds"
1015)
@@ -14,6 +19,12 @@ import (
1419type ReferencedInferencePool struct {
1520 // Source is the original InferencePool that this ReferencedInferencePool is based on.
1621 Source * inference.InferencePool
22+ // Gateways are the Gateways that this ReferencedInferencePool is attached to.
23+ Gateways []* apiv1.Gateway
24+ // HTTPRoutes are the HTTPRoutes that reference this InferencePool.
25+ HTTPRoutes []* L7Route
26+ // Conditions contains the conditions that should be applied to the InferencePool.
27+ Conditions []conditions.Condition
1728}
1829
1930// buildReferencedInferencePools builds a map of InferencePools that are referenced by HTTPRoutes
@@ -22,8 +33,9 @@ func buildReferencedInferencePools(
2233 routes map [RouteKey ]* L7Route ,
2334 gws map [types.NamespacedName ]* Gateway ,
2435 inferencePools map [types.NamespacedName ]* inference.InferencePool ,
36+ services map [types.NamespacedName ]* v1.Service ,
2537) map [types.NamespacedName ]* ReferencedInferencePool {
26- referencedInferencePools := make (map [types.NamespacedName ]* ReferencedInferencePool )
38+ referencedInferencePools := make (map [types.NamespacedName ]* ReferencedInferencePool , len ( inferencePools ) )
2739
2840 for _ , gw := range gws {
2941 if gw == nil {
@@ -37,6 +49,20 @@ func buildReferencedInferencePools(
3749 return nil
3850 }
3951
52+ // validate each referenced InferencePool and add conditions.
53+ for _ , refPool := range referencedInferencePools {
54+ routeCond := validateInferencePoolRoutesAcceptance (refPool .Source , refPool .HTTPRoutes )
55+
56+ if routeCond != nil {
57+ refPool .Conditions = append (refPool .Conditions , * routeCond )
58+ }
59+
60+ extensionRefCond := validateInferencePoolExtensionRef (refPool .Source , services )
61+ if extensionRefCond != nil {
62+ refPool .Conditions = append (refPool .Conditions , * extensionRefCond )
63+ }
64+ }
65+
4066 return referencedInferencePools
4167}
4268
@@ -48,8 +74,9 @@ func processInferencePoolsForGateway(
4874 inferencePools map [types.NamespacedName ]* inference.InferencePool ,
4975) {
5076 gwKey := client .ObjectKeyFromObject (gw .Source )
77+
5178 for _ , route := range routes {
52- if ! route . Valid || ! routeBelongsToGateway (route .ParentRefs , gwKey ) {
79+ if ! routeBelongsToGateway (route .ParentRefs , gwKey ) {
5380 continue
5481 }
5582
@@ -70,13 +97,83 @@ func processInferencePoolsForGateway(
7097 }
7198
7299 if _ , referenced := referencedInferencePools [poolName ]; ! referenced {
73- referencedInferencePools [poolName ] = & ReferencedInferencePool {}
100+ referencedInferencePools [poolName ] = & ReferencedInferencePool {
101+ Conditions : make ([]conditions.Condition , 0 , 2 ),
102+ Gateways : make ([]* apiv1.Gateway , 0 ),
103+ HTTPRoutes : make ([]* L7Route , 0 ),
104+ }
74105 }
75106
76107 if pool , exists := inferencePools [poolName ]; exists {
77108 referencedInferencePools [poolName ].Source = pool
109+ referencedInferencePools [poolName ].Gateways = append (
110+ referencedInferencePools [poolName ].Gateways ,
111+ gw .Source ,
112+ )
113+ referencedInferencePools [poolName ].HTTPRoutes = append (
114+ referencedInferencePools [poolName ].HTTPRoutes ,
115+ route ,
116+ )
78117 }
79118 }
80119 }
81120 }
82121}
122+
123+ // validateInferencePoolExtensionRef validates the ExtensionRef of the InferencePool.
124+ func validateInferencePoolExtensionRef (
125+ ip * inference.InferencePool ,
126+ svc map [types.NamespacedName ]* v1.Service ,
127+ ) * conditions.Condition {
128+ var failingCond conditions.Condition
129+ if ip == nil {
130+ return nil
131+ }
132+
133+ // if kind is empty, it defaults to Service
134+ kind := string (ip .Spec .EndpointPickerRef .Kind )
135+ if kind == "" {
136+ kind = kinds .Service
137+ }
138+
139+ if kind != kinds .Service {
140+ failingCond = conditions .NewInferencePoolInvalidExtensionref ("Invalid ExtensionRef kind: " + kind )
141+ return & failingCond
142+ }
143+
144+ eppNsName := types.NamespacedName {
145+ Name : string (ip .Spec .EndpointPickerRef .Name ),
146+ Namespace : ip .GetNamespace (),
147+ }
148+
149+ if _ , ok := svc [eppNsName ]; ! ok {
150+ failingCond = conditions .NewInferencePoolInvalidExtensionref ("ExtensionRef Service not found: " + eppNsName .String ())
151+ return & failingCond
152+ }
153+
154+ return nil
155+ }
156+
157+ // validateInferencePoolRoutesAcceptance checks if the routes that reference the InferencePool
158+ // are accepted by the Gateway.
159+ func validateInferencePoolRoutesAcceptance (ip * inference.InferencePool , routes []* L7Route ) * conditions.Condition {
160+ if ip == nil || len (routes ) == 0 {
161+ return nil
162+ }
163+
164+ // we do not to validate that the route belongs to the gateway or not
165+ // we only process routes that belong to the gateway in the first place
166+ for _ , route := range routes {
167+ if ! route .Valid {
168+ cond := conditions .NewInferencePoolInvalidHTTPRouteNotAccepted (
169+ fmt .Sprintf ("Referenced HTTPRoute %s/%s is not accepted by the Gateway" ,
170+ route .Source .GetNamespace (),
171+ route .Source .GetName (),
172+ ),
173+ )
174+ return & cond
175+ }
176+ }
177+
178+ return nil
179+ }
0 commit comments