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,17 @@ func buildReferencedInferencePools(
3749 return nil
3850 }
3951
52+ // validate each referenced InferencePool and add conditions.
53+ for _ , refPool := range referencedInferencePools {
54+ if routeCond := validateInferencePoolRoutesAcceptance (refPool .Source , refPool .HTTPRoutes ); routeCond != nil {
55+ refPool .Conditions = append (refPool .Conditions , * routeCond )
56+ }
57+
58+ if extensionRefCond := validateInferencePoolExtensionRef (refPool .Source , services ); extensionRefCond != nil {
59+ refPool .Conditions = append (refPool .Conditions , * extensionRefCond )
60+ }
61+ }
62+
4063 return referencedInferencePools
4164}
4265
@@ -48,8 +71,9 @@ func processInferencePoolsForGateway(
4871 inferencePools map [types.NamespacedName ]* inference.InferencePool ,
4972) {
5073 gwKey := client .ObjectKeyFromObject (gw .Source )
74+
5175 for _ , route := range routes {
52- if ! route . Valid || ! routeBelongsToGateway (route .ParentRefs , gwKey ) {
76+ if ! routeBelongsToGateway (route .ParentRefs , gwKey ) {
5377 continue
5478 }
5579
@@ -70,13 +94,83 @@ func processInferencePoolsForGateway(
7094 }
7195
7296 if _ , referenced := referencedInferencePools [poolName ]; ! referenced {
73- referencedInferencePools [poolName ] = & ReferencedInferencePool {}
97+ referencedInferencePools [poolName ] = & ReferencedInferencePool {
98+ Conditions : make ([]conditions.Condition , 0 , 2 ),
99+ Gateways : make ([]* apiv1.Gateway , 0 ),
100+ HTTPRoutes : make ([]* L7Route , 0 ),
101+ }
74102 }
75103
76104 if pool , exists := inferencePools [poolName ]; exists {
77105 referencedInferencePools [poolName ].Source = pool
106+ referencedInferencePools [poolName ].Gateways = append (
107+ referencedInferencePools [poolName ].Gateways ,
108+ gw .Source ,
109+ )
110+ referencedInferencePools [poolName ].HTTPRoutes = append (
111+ referencedInferencePools [poolName ].HTTPRoutes ,
112+ route ,
113+ )
78114 }
79115 }
80116 }
81117 }
82118}
119+
120+ // validateInferencePoolExtensionRef validates the ExtensionRef of the InferencePool.
121+ func validateInferencePoolExtensionRef (
122+ ip * inference.InferencePool ,
123+ svc map [types.NamespacedName ]* v1.Service ,
124+ ) * conditions.Condition {
125+ var failingCond conditions.Condition
126+ if ip == nil {
127+ return nil
128+ }
129+
130+ // if kind is empty, it defaults to Service
131+ kind := string (ip .Spec .EndpointPickerRef .Kind )
132+ if kind == "" {
133+ kind = kinds .Service
134+ }
135+
136+ if kind != kinds .Service {
137+ failingCond = conditions .NewInferencePoolInvalidExtensionref ("Invalid ExtensionRef kind: " + kind )
138+ return & failingCond
139+ }
140+
141+ eppNsName := types.NamespacedName {
142+ Name : string (ip .Spec .EndpointPickerRef .Name ),
143+ Namespace : ip .GetNamespace (),
144+ }
145+
146+ if _ , ok := svc [eppNsName ]; ! ok {
147+ failingCond = conditions .NewInferencePoolInvalidExtensionref ("ExtensionRef Service not found: " + eppNsName .String ())
148+ return & failingCond
149+ }
150+
151+ return nil
152+ }
153+
154+ // validateInferencePoolRoutesAcceptance checks if the routes that reference the InferencePool
155+ // are accepted by the Gateway.
156+ func validateInferencePoolRoutesAcceptance (ip * inference.InferencePool , routes []* L7Route ) * conditions.Condition {
157+ if ip == nil || len (routes ) == 0 {
158+ return nil
159+ }
160+
161+ // we do not need to validate that the route belongs to the gateway or not
162+ // we only process routes that belong to the gateway in the first place
163+ for _ , route := range routes {
164+ if ! route .Valid {
165+ cond := conditions .NewInferencePoolInvalidHTTPRouteNotAccepted (
166+ fmt .Sprintf ("Referenced HTTPRoute %s/%s is not accepted by the Gateway" ,
167+ route .Source .GetNamespace (),
168+ route .Source .GetName (),
169+ ),
170+ )
171+ return & cond
172+ }
173+ }
174+
175+ return nil
176+ }
0 commit comments