@@ -31,10 +31,11 @@ var httpRouteGVR = schema.GroupVersionResource{
3131}
3232
3333type gatewayDataPlaneReport struct {
34- ListenerAttachedRoutes []string
35- AttachedHTTPRoutes int
36- MatchingEndpointSlices int
37- ReadyEndpoints int
34+ ListenerCount int
35+ AttachedHTTPRoutes int
36+ TotalHTTPRoutes int
37+ MatchingEndpointSlice int
38+ ReadyEndpoints int
3839}
3940
4041func init () {
@@ -61,6 +62,8 @@ func CheckInferenceGateway(ctx *checks.ValidationContext) error {
6162 return err
6263 }
6364
65+ collectGatewayControlPlaneArtifacts (ctx )
66+
6467 // 1. GatewayClass "kgateway" accepted
6568 gcGVR := schema.GroupVersionResource {
6669 Group : "gateway.networking.k8s.io" , Version : "v1" , Resource : "gatewayclasses" ,
@@ -74,13 +77,15 @@ func CheckInferenceGateway(ctx *checks.ValidationContext) error {
7477 return errors .Wrap (errors .ErrCodeInternal , "GatewayClass not accepted" , condErr )
7578 }
7679 if gcCond .Status != "True" {
77- return errors .Wrap (errors .ErrCodeInternal , "GatewayClass not accepted" ,
78- errors . New ( errors . ErrCodeInternal ,
79- fmt . Sprintf ( "condition Accepted=%s (want True)" , gcCond .Status ) ))
80+ return errors .New (errors .ErrCodeInternal ,
81+ fmt . Sprintf ( "GatewayClass not accepted: status=%s reason=%s message=%s" ,
82+ gcCond . Status , gcCond . Reason , gcCond .Message ))
8083 }
81- recordArtifact (ctx , "GatewayClass Status" ,
82- fmt .Sprintf ("Name: %s\n Accepted: %s\n Reason: %s\n Message: %s" ,
83- gc .GetName (), gcCond .Status , gcCond .Reason , gcCond .Message ))
84+ controllerName , _ , _ := unstructured .NestedString (gc .Object , "spec" , "controllerName" )
85+ recordRawTextArtifact (ctx , "GatewayClass" ,
86+ "kubectl get gatewayclass kgateway -o yaml" ,
87+ fmt .Sprintf ("Name: %s\n ControllerName: %s\n Accepted: %s\n Reason: %s\n Message: %s" ,
88+ gc .GetName (), valueOrUnknown (controllerName ), gcCond .Status , gcCond .Reason , gcCond .Message ))
8489
8590 // 2. Gateway "inference-gateway" programmed
8691 gwGVR := schema.GroupVersionResource {
@@ -96,13 +101,21 @@ func CheckInferenceGateway(ctx *checks.ValidationContext) error {
96101 return errors .Wrap (errors .ErrCodeInternal , "Gateway not programmed" , condErr )
97102 }
98103 if gwCond .Status != "True" {
99- return errors .Wrap (errors .ErrCodeInternal , "Gateway not programmed" ,
100- errors .New (errors .ErrCodeInternal ,
101- fmt .Sprintf ("condition Programmed=%s (want True)" , gwCond .Status )))
104+ return errors .New (errors .ErrCodeInternal ,
105+ fmt .Sprintf ("Gateway not programmed: status=%s reason=%s message=%s" ,
106+ gwCond .Status , gwCond .Reason , gwCond .Message ))
107+ }
108+ addresses , found , _ := unstructured .NestedSlice (gw .Object , "status" , "addresses" )
109+ addressCount := 0
110+ if found {
111+ addressCount = len (addresses )
102112 }
103- recordArtifact (ctx , "Gateway Status" ,
104- fmt .Sprintf ("Name: %s\n Namespace: %s\n Programmed: %s\n Reason: %s\n Message: %s" ,
105- gw .GetName (), gw .GetNamespace (), gwCond .Status , gwCond .Reason , gwCond .Message ))
113+ recordRawTextArtifact (ctx , "Gateways" ,
114+ "kubectl get gateways -A" ,
115+ fmt .Sprintf ("Name: %s/%s\n Programmed: %s\n Reason: %s\n Message: %s\n AddressCount: %d" ,
116+ gw .GetNamespace (), gw .GetName (), gwCond .Status , gwCond .Reason , gwCond .Message , addressCount ))
117+ recordObjectYAMLArtifact (ctx , "Gateway details" ,
118+ "kubectl get gateway inference-gateway -n kgateway-system -o yaml" , gw .Object )
106119
107120 // 3. Required CRDs exist
108121 crdGVR := schema.GroupVersionResource {
@@ -115,28 +128,25 @@ func CheckInferenceGateway(ctx *checks.ValidationContext) error {
115128 }
116129 var crdSummary strings.Builder
117130 for _ , crdName := range requiredCRDs {
118- _ , crdErr := dynClient .Resource (crdGVR ).Get (ctx .Context , crdName , metav1.GetOptions {})
119- if crdErr != nil {
131+ _ , err := dynClient .Resource (crdGVR ).Get (ctx .Context , crdName , metav1.GetOptions {})
132+ if err != nil {
120133 return errors .Wrap (errors .ErrCodeNotFound ,
121- fmt .Sprintf ("CRD %s not found" , crdName ), crdErr )
134+ fmt .Sprintf ("CRD %s not found" , crdName ), err )
122135 }
123136 fmt .Fprintf (& crdSummary , " %s: present\n " , crdName )
124137 }
125- recordArtifact (ctx , "Required CRDs" , crdSummary .String ())
138+ recordRawTextArtifact (ctx , "Required CRDs" , " " , crdSummary .String ())
126139
127140 // 4. Gateway data-plane readiness (behavioral validation).
128- dpReport , err := validateGatewayDataPlane (ctx )
141+ report , err := validateGatewayDataPlane (ctx )
129142 if err != nil {
130143 return err
131144 }
132-
133- listenerSummary := "none"
134- if len (dpReport .ListenerAttachedRoutes ) > 0 {
135- listenerSummary = strings .Join (dpReport .ListenerAttachedRoutes , ", " )
136- }
137- recordArtifact (ctx , "Gateway Data Plane" ,
138- fmt .Sprintf ("Listeners: %s\n Attached HTTPRoutes: %d\n Matching EndpointSlices: %d\n Ready Endpoints: %d" ,
139- listenerSummary , dpReport .AttachedHTTPRoutes , dpReport .MatchingEndpointSlices , dpReport .ReadyEndpoints ))
145+ recordRawTextArtifact (ctx , "Gateway Data Plane" ,
146+ "kubectl get endpointslices -n kgateway-system" ,
147+ fmt .Sprintf ("Listeners: %d\n Attached HTTPRoutes: %d\n HTTPRoutes (all): %d\n Matching EndpointSlices: %d\n Ready endpoints: %d" ,
148+ report .ListenerCount , report .AttachedHTTPRoutes , report .TotalHTTPRoutes ,
149+ report .MatchingEndpointSlice , report .ReadyEndpoints ))
140150 return nil
141151}
142152
@@ -164,12 +174,12 @@ func validateGatewayDataPlane(ctx *checks.ValidationContext) (*gatewayDataPlaneR
164174 if gwErr == nil {
165175 listeners , found , _ := unstructured .NestedSlice (gw .Object , "status" , "listeners" )
166176 if found {
177+ report .ListenerCount = len (listeners )
167178 for _ , l := range listeners {
168179 if lMap , ok := l .(map [string ]interface {}); ok {
169180 name , _ , _ := unstructured .NestedString (lMap , "name" )
170181 attached , _ , _ := unstructured .NestedInt64 (lMap , "attachedRoutes" )
171- report .ListenerAttachedRoutes = append (report .ListenerAttachedRoutes ,
172- fmt .Sprintf ("%s=%d" , name , attached ))
182+ report .AttachedHTTPRoutes += int (attached )
173183 slog .Info ("gateway listener status" , "listener" , name , "attachedRoutes" , attached )
174184 }
175185 }
@@ -180,6 +190,7 @@ func validateGatewayDataPlane(ctx *checks.ValidationContext) (*gatewayDataPlaneR
180190 httpRouteList , listErr := dynClient .Resource (httpRouteGVR ).Namespace ("" ).List (
181191 ctx .Context , metav1.ListOptions {})
182192 if listErr == nil {
193+ report .TotalHTTPRoutes = len (httpRouteList .Items )
183194 var attached int
184195 for _ , route := range httpRouteList .Items {
185196 parentRefs , found , _ := unstructured .NestedSlice (route .Object , "spec" , "parentRefs" )
@@ -215,7 +226,7 @@ func validateGatewayDataPlane(ctx *checks.ValidationContext) (*gatewayDataPlaneR
215226 if ! strings .Contains (svcName , "inference-gateway" ) {
216227 continue
217228 }
218- report .MatchingEndpointSlices ++
229+ report .MatchingEndpointSlice ++
219230 for _ , ep := range slice .Endpoints {
220231 if ep .Conditions .Ready != nil && * ep .Conditions .Ready {
221232 report .ReadyEndpoints ++
@@ -230,3 +241,40 @@ func validateGatewayDataPlane(ctx *checks.ValidationContext) (*gatewayDataPlaneR
230241
231242 return report , nil
232243}
244+
245+ func collectGatewayControlPlaneArtifacts (ctx * checks.ValidationContext ) {
246+ if ctx .Clientset == nil {
247+ return
248+ }
249+
250+ deploys , deployErr := ctx .Clientset .AppsV1 ().Deployments ("kgateway-system" ).List (
251+ ctx .Context , metav1.ListOptions {})
252+ if deployErr != nil {
253+ recordRawTextArtifact (ctx , "kgateway deployments" , "kubectl get deploy -n kgateway-system" ,
254+ fmt .Sprintf ("failed to list deployments: %v" , deployErr ))
255+ } else {
256+ var deploymentSummary strings.Builder
257+ for _ , d := range deploys .Items {
258+ expected := int32 (1 )
259+ if d .Spec .Replicas != nil {
260+ expected = * d .Spec .Replicas
261+ }
262+ fmt .Fprintf (& deploymentSummary , "%-40s available=%d/%d image=%s\n " ,
263+ d .Name , d .Status .AvailableReplicas , expected , firstContainerImage (d .Spec .Template .Spec .Containers ))
264+ }
265+ recordRawTextArtifact (ctx , "kgateway deployments" , "kubectl get deploy -n kgateway-system" , deploymentSummary .String ())
266+ }
267+
268+ pods , podErr := ctx .Clientset .CoreV1 ().Pods ("kgateway-system" ).List (ctx .Context , metav1.ListOptions {})
269+ if podErr != nil {
270+ recordRawTextArtifact (ctx , "kgateway pods" , "kubectl get pods -n kgateway-system" ,
271+ fmt .Sprintf ("failed to list pods: %v" , podErr ))
272+ return
273+ }
274+ var podSummary strings.Builder
275+ for _ , pod := range pods .Items {
276+ fmt .Fprintf (& podSummary , "%-48s ready=%s phase=%s node=%s\n " ,
277+ pod .Name , podReadyCount (pod ), pod .Status .Phase , valueOrUnknown (pod .Spec .NodeName ))
278+ }
279+ recordRawTextArtifact (ctx , "kgateway pods" , "kubectl get pods -n kgateway-system" , podSummary .String ())
280+ }
0 commit comments