From 1e89b8db740998fe2a939730d0150e0d4b3d76f0 Mon Sep 17 00:00:00 2001 From: Sascha Schwarze Date: Thu, 29 Aug 2024 17:17:16 +0200 Subject: [PATCH] Ensure ContainerHealthy condition is set back to True Co-authored-by: Matthias Diester --- .../revision/reconcile_resources.go | 4 ++ pkg/reconciler/revision/table_test.go | 53 +++++++++++++++++++ pkg/testing/v1/revision.go | 6 +++ 3 files changed, 63 insertions(+) diff --git a/pkg/reconciler/revision/reconcile_resources.go b/pkg/reconciler/revision/reconcile_resources.go index 3fa6f07d24fe..c7b18ac3b8df 100644 --- a/pkg/reconciler/revision/reconcile_resources.go +++ b/pkg/reconciler/revision/reconcile_resources.go @@ -117,6 +117,10 @@ func (c *Reconciler) reconcileDeployment(ctx context.Context, rev *v1.Revision) } } + if *deployment.Spec.Replicas > 0 && *deployment.Spec.Replicas == deployment.Status.ReadyReplicas { + rev.Status.MarkContainerHealthyTrue() + } + return nil } diff --git a/pkg/reconciler/revision/table_test.go b/pkg/reconciler/revision/table_test.go index c534b56e7ed8..6ec8ee90a2d0 100644 --- a/pkg/reconciler/revision/table_test.go +++ b/pkg/reconciler/revision/table_test.go @@ -41,6 +41,7 @@ import ( tracingconfig "knative.dev/pkg/tracing/config" autoscalingv1alpha1 "knative.dev/serving/pkg/apis/autoscaling/v1alpha1" defaultconfig "knative.dev/serving/pkg/apis/config" + "knative.dev/serving/pkg/apis/serving" v1 "knative.dev/serving/pkg/apis/serving/v1" "knative.dev/serving/pkg/autoscaler/config/autoscalerconfig" servingclient "knative.dev/serving/pkg/client/injection/client" @@ -742,6 +743,38 @@ func TestReconcile(t *testing.T) { PodSpecPersistentVolumeClaim: defaultconfig.Enabled, PodSpecPersistentVolumeWrite: defaultconfig.Enabled, }}), + }, { + Name: "revision's ContainerHealthy turns back to True if the deployment is healthy", + Objects: []runtime.Object{ + Revision("foo", "container-unhealthy", + WithLogURL, + MarkRevisionReady, + withDefaultContainerStatuses(), + WithRevisionLabel(serving.RoutingStateLabelKey, "active"), + MarkContainerHealthyFalse("ExitCode137"), + ), + pa("foo", "container-unhealthy", + WithPASKSReady, + WithScaleTargetInitialized, + WithTraffic, + WithReachabilityReachable, + WithPAStatusService("something"), + ), + readyDeploy(deploy(t, "foo", "container-unhealthy", withReplicas(1))), + image("foo", "container-unhealthy"), + }, + Key: "foo/container-unhealthy", + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: Revision("foo", "container-unhealthy", + WithLogURL, + MarkRevisionReady, + withDefaultContainerStatuses(), + WithRevisionLabel(serving.RoutingStateLabelKey, "active"), + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "RevisionReady", "Revision becomes ready upon all resources being ready"), + }, }} table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, _ configmap.Watcher) controller.Reconciler { @@ -851,6 +884,19 @@ func allUnknownConditions(r *v1.Revision) { type configOption func(*config.Config) +type deploymentOption func(*appsv1.Deployment) + +// withReplicas configures the number of replicas on the Deployment +func withReplicas(replicas int32) deploymentOption { + return func(d *appsv1.Deployment) { + d.Spec.Replicas = &replicas + d.Status.AvailableReplicas = replicas + d.Status.ReadyReplicas = replicas + d.Status.Replicas = replicas + d.Status.UpdatedReplicas = replicas + } +} + func deploy(t *testing.T, namespace, name string, opts ...interface{}) *appsv1.Deployment { t.Helper() cfg := reconcilerTestConfig() @@ -876,6 +922,13 @@ func deploy(t *testing.T, namespace, name string, opts ...interface{}) *appsv1.D if err != nil { t.Fatal("failed to create deployment") } + + for _, opt := range opts { + if deploymentOpt, ok := opt.(deploymentOption); ok { + deploymentOpt(deployment) + } + } + return deployment } diff --git a/pkg/testing/v1/revision.go b/pkg/testing/v1/revision.go index a3cd452fd9ef..6591c3dc3797 100644 --- a/pkg/testing/v1/revision.go +++ b/pkg/testing/v1/revision.go @@ -158,6 +158,12 @@ func MarkContainerHealthyUnknown(reason string) RevisionOption { } } +func MarkContainerHealthyFalse(reason string) RevisionOption { + return func(r *v1.Revision) { + r.Status.MarkContainerHealthyFalse(reason, "") + } +} + // MarkProgressDeadlineExceeded calls the method of the same name on the Revision // with the message we expect the Revision Reconciler to pass. func MarkProgressDeadlineExceeded(message string) RevisionOption {