Skip to content

Commit c22bf13

Browse files
committed
Ensure we don't reconcile an invalid pod template spec.
Signed-off-by: Juan Antonio Osorio <[email protected]>
1 parent e275977 commit c22bf13

File tree

2 files changed

+40
-18
lines changed

2 files changed

+40
-18
lines changed

cmd/thv-operator/controllers/mcpserver_controller.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,12 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
298298
err = r.Get(ctx, types.NamespacedName{Name: mcpServer.Name, Namespace: mcpServer.Namespace}, deployment)
299299
if err != nil && errors.IsNotFound(err) {
300300
// Validate PodTemplateSpec and update status
301-
r.validateAndUpdatePodTemplateStatus(ctx, mcpServer)
301+
if !r.validateAndUpdatePodTemplateStatus(ctx, mcpServer) {
302+
// Invalid PodTemplateSpec - return without error to avoid infinite retries
303+
// The user must fix the spec and the next reconciliation will retry
304+
ctxLogger.Info("Skipping deployment creation due to invalid PodTemplateSpec")
305+
return ctrl.Result{}, nil
306+
}
302307

303308
// Define a new deployment
304309
dep := r.deploymentForMCPServer(ctx, mcpServer)
@@ -370,7 +375,12 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
370375
// Check if the deployment spec changed
371376
if r.deploymentNeedsUpdate(ctx, deployment, mcpServer) {
372377
// Validate PodTemplateSpec and update status
373-
r.validateAndUpdatePodTemplateStatus(ctx, mcpServer)
378+
if !r.validateAndUpdatePodTemplateStatus(ctx, mcpServer) {
379+
// Invalid PodTemplateSpec - return without error to avoid infinite retries
380+
// The user must fix the spec and the next reconciliation will retry
381+
ctxLogger.Info("Skipping deployment update due to invalid PodTemplateSpec")
382+
return ctrl.Result{}, nil
383+
}
374384

375385
// Update the deployment
376386
newDeployment := r.deploymentForMCPServer(ctx, mcpServer)
@@ -416,43 +426,55 @@ func setImageValidationCondition(mcpServer *mcpv1alpha1.MCPServer, status metav1
416426

417427
// validateAndUpdatePodTemplateStatus validates the PodTemplateSpec and updates the MCPServer status
418428
// with appropriate conditions and events
419-
func (r *MCPServerReconciler) validateAndUpdatePodTemplateStatus(ctx context.Context, mcpServer *mcpv1alpha1.MCPServer) {
429+
func (r *MCPServerReconciler) validateAndUpdatePodTemplateStatus(ctx context.Context, mcpServer *mcpv1alpha1.MCPServer) bool {
420430
ctxLogger := log.FromContext(ctx)
421431

422432
// Only validate if PodTemplateSpec is provided
423433
if mcpServer.Spec.PodTemplateSpec == nil || mcpServer.Spec.PodTemplateSpec.Raw == nil {
424-
return
434+
// No PodTemplateSpec provided, validation passes
435+
return true
425436
}
426437

427438
_, err := NewMCPServerPodTemplateSpecBuilder(mcpServer.Spec.PodTemplateSpec)
428439
if err != nil {
429440
// Record event for invalid PodTemplateSpec
430441
r.Recorder.Eventf(mcpServer, corev1.EventTypeWarning, "InvalidPodTemplateSpec",
431-
"Failed to parse PodTemplateSpec: %v. Deployment will continue without pod customizations.", err)
442+
"Failed to parse PodTemplateSpec: %v. Deployment blocked until PodTemplateSpec is fixed.", err)
432443

433444
// Set condition for invalid PodTemplateSpec
434445
meta.SetStatusCondition(&mcpServer.Status.Conditions, metav1.Condition{
435446
Type: "PodTemplateValid",
436447
Status: metav1.ConditionFalse,
437448
ObservedGeneration: mcpServer.Generation,
438449
Reason: "InvalidPodTemplateSpec",
439-
Message: fmt.Sprintf("Failed to parse PodTemplateSpec: %v. Deployment continues without customizations.", err),
440-
})
441-
} else {
442-
// Set condition for valid PodTemplateSpec
443-
meta.SetStatusCondition(&mcpServer.Status.Conditions, metav1.Condition{
444-
Type: "PodTemplateValid",
445-
Status: metav1.ConditionTrue,
446-
ObservedGeneration: mcpServer.Generation,
447-
Reason: "ValidPodTemplateSpec",
448-
Message: "PodTemplateSpec is valid",
450+
Message: fmt.Sprintf("Failed to parse PodTemplateSpec: %v. Deployment blocked until fixed.", err),
449451
})
452+
453+
// Update status with the condition
454+
if statusErr := r.Status().Update(ctx, mcpServer); statusErr != nil {
455+
ctxLogger.Error(statusErr, "Failed to update MCPServer status with PodTemplateSpec validation")
456+
}
457+
458+
ctxLogger.Error(err, "PodTemplateSpec validation failed")
459+
return false
450460
}
451461

462+
// Set condition for valid PodTemplateSpec
463+
meta.SetStatusCondition(&mcpServer.Status.Conditions, metav1.Condition{
464+
Type: "PodTemplateValid",
465+
Status: metav1.ConditionTrue,
466+
ObservedGeneration: mcpServer.Generation,
467+
Reason: "ValidPodTemplateSpec",
468+
Message: "PodTemplateSpec is valid",
469+
})
470+
452471
// Update status with the condition
453472
if statusErr := r.Status().Update(ctx, mcpServer); statusErr != nil {
454473
ctxLogger.Error(statusErr, "Failed to update MCPServer status with PodTemplateSpec validation")
455474
}
475+
476+
ctxLogger.V(1).Info("PodTemplateSpec validation completed successfully")
477+
return true
456478
}
457479

458480
// handleRestartAnnotation checks if the restart annotation has been updated and triggers a restart if needed

cmd/thv-operator/controllers/mcpserver_invalid_podtemplate_integration_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ func TestMCPServerReconciler_InvalidPodTemplateSpec(t *testing.T) {
132132

133133
// Reconcile
134134
_, err := r.Reconcile(ctx, req)
135-
// We expect the reconciliation to succeed even with invalid PodTemplateSpec
136-
// as it should continue without customizations
135+
// We expect the reconciliation to succeed (no error) even with invalid PodTemplateSpec
136+
// to avoid infinite retries. The deployment should not be created though.
137137
require.NoError(t, err)
138138

139139
// Check the MCPServer status conditions
@@ -150,7 +150,7 @@ func TestMCPServerReconciler_InvalidPodTemplateSpec(t *testing.T) {
150150

151151
if tt.expectConditionStatus == metav1.ConditionFalse {
152152
assert.Contains(t, condition.Message, "Failed to parse PodTemplateSpec")
153-
assert.Contains(t, condition.Message, "Deployment continues without customizations")
153+
assert.Contains(t, condition.Message, "Deployment blocked until fixed")
154154
}
155155
}
156156

0 commit comments

Comments
 (0)