1
1
package graph
2
2
3
3
import (
4
+ "fmt"
5
+
6
+ v1 "k8s.io/api/core/v1"
4
7
"k8s.io/apimachinery/pkg/types"
5
8
"sigs.k8s.io/controller-runtime/pkg/client"
6
9
inference "sigs.k8s.io/gateway-api-inference-extension/api/v1"
10
+ apiv1 "sigs.k8s.io/gateway-api/apis/v1"
7
11
12
+ "github.com/nginx/nginx-gateway-fabric/v2/internal/controller/state/conditions"
8
13
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/controller"
9
14
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/kinds"
10
15
)
@@ -14,6 +19,12 @@ import (
14
19
type ReferencedInferencePool struct {
15
20
// Source is the original InferencePool that this ReferencedInferencePool is based on.
16
21
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
17
28
}
18
29
19
30
// buildReferencedInferencePools builds a map of InferencePools that are referenced by HTTPRoutes
@@ -22,8 +33,9 @@ func buildReferencedInferencePools(
22
33
routes map [RouteKey ]* L7Route ,
23
34
gws map [types.NamespacedName ]* Gateway ,
24
35
inferencePools map [types.NamespacedName ]* inference.InferencePool ,
36
+ services map [types.NamespacedName ]* v1.Service ,
25
37
) map [types.NamespacedName ]* ReferencedInferencePool {
26
- referencedInferencePools := make (map [types.NamespacedName ]* ReferencedInferencePool )
38
+ referencedInferencePools := make (map [types.NamespacedName ]* ReferencedInferencePool , len ( inferencePools ) )
27
39
28
40
for _ , gw := range gws {
29
41
if gw == nil {
@@ -37,6 +49,17 @@ func buildReferencedInferencePools(
37
49
return nil
38
50
}
39
51
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
+
40
63
return referencedInferencePools
41
64
}
42
65
@@ -48,8 +71,9 @@ func processInferencePoolsForGateway(
48
71
inferencePools map [types.NamespacedName ]* inference.InferencePool ,
49
72
) {
50
73
gwKey := client .ObjectKeyFromObject (gw .Source )
74
+
51
75
for _ , route := range routes {
52
- if ! route . Valid || ! routeBelongsToGateway (route .ParentRefs , gwKey ) {
76
+ if ! routeBelongsToGateway (route .ParentRefs , gwKey ) {
53
77
continue
54
78
}
55
79
@@ -70,13 +94,83 @@ func processInferencePoolsForGateway(
70
94
}
71
95
72
96
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
+ }
74
102
}
75
103
76
104
if pool , exists := inferencePools [poolName ]; exists {
77
105
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
+ )
78
114
}
79
115
}
80
116
}
81
117
}
82
118
}
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