From 3ae54d9c3b768d2caff78a7605d450c66dd1c09f Mon Sep 17 00:00:00 2001 From: Tara Gu Date: Mon, 15 Jul 2019 15:54:24 -0400 Subject: [PATCH 1/2] Update reconciler to update observed generation when ready status is False --- pkg/reconciler/route/route.go | 4 ++ test/e2e/image_pull_error_test.go | 2 +- test/e2e/pod_schedule_error_test.go | 2 +- test/e2e/route_service_test.go | 90 +++++++++++++++++++++++++++++ test/v1alpha1/service.go | 15 ++++- 5 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 test/e2e/route_service_test.go diff --git a/pkg/reconciler/route/route.go b/pkg/reconciler/route/route.go index 95985bd8ff30..0102b1a7aeab 100644 --- a/pkg/reconciler/route/route.go +++ b/pkg/reconciler/route/route.go @@ -233,6 +233,10 @@ func (c *Reconciler) reconcile(ctx context.Context, r *v1alpha1.Route) error { traffic, err := c.configureTraffic(ctx, r, clusterLocalServiceNames) if traffic == nil || err != nil { // Traffic targets aren't ready, no need to configure child resources. + // Need to update ObservedGeneration, otherwise Route's Ready state won't + // be propagated to Service and the Service's RoutesReady will stay in + // 'Unknown'. + r.Status.ObservedGeneration = r.Generation return err } diff --git a/test/e2e/image_pull_error_test.go b/test/e2e/image_pull_error_test.go index 8b84d57e26a0..660eb9f540a4 100644 --- a/test/e2e/image_pull_error_test.go +++ b/test/e2e/image_pull_error_test.go @@ -56,7 +56,7 @@ func TestImagePullError(t *testing.T) { names.Config = serviceresourcenames.Configuration(svc) err = v1a1test.WaitForServiceState(clients.ServingAlphaClient, names.Service, func(r *v1alpha1.Service) (bool, error) { - cond := r.Status.GetCondition(v1alpha1.ConfigurationConditionReady) + cond := r.Status.GetCondition(v1alpha1.ServiceConditionConfigurationsReady) if cond != nil && !cond.IsUnknown() { if cond.IsFalse() { if cond.Reason == "RevisionFailed" { diff --git a/test/e2e/pod_schedule_error_test.go b/test/e2e/pod_schedule_error_test.go index c04b629dc154..5131cb123fad 100644 --- a/test/e2e/pod_schedule_error_test.go +++ b/test/e2e/pod_schedule_error_test.go @@ -72,7 +72,7 @@ func TestPodScheduleError(t *testing.T) { names.Config = serviceresourcenames.Configuration(svc) err = v1a1test.WaitForServiceState(clients.ServingAlphaClient, names.Service, func(r *v1alpha1.Service) (bool, error) { - cond := r.Status.GetCondition(v1alpha1.ConfigurationConditionReady) + cond := r.Status.GetCondition(v1alpha1.ServiceConditionConfigurationsReady) if cond != nil && !cond.IsUnknown() { if strings.Contains(cond.Message, errorMsg) && cond.IsFalse() { return true, nil diff --git a/test/e2e/route_service_test.go b/test/e2e/route_service_test.go new file mode 100644 index 000000000000..9838c93215c1 --- /dev/null +++ b/test/e2e/route_service_test.go @@ -0,0 +1,90 @@ +// +build e2e + +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "testing" + + "knative.dev/serving/pkg/apis/serving/v1alpha1" + "knative.dev/serving/pkg/apis/serving/v1beta1" + "knative.dev/serving/test" + v1a1test "knative.dev/serving/test/v1alpha1" + "knative.dev/pkg/test/logstream" + "knative.dev/pkg/apis" + serviceresourcenames "knative.dev/serving/pkg/reconciler/service/resources/names" + . "knative.dev/serving/pkg/testing/v1alpha1" +) + +var serviceCondSet = apis.NewLivingConditionSet( + v1alpha1.ServiceConditionConfigurationsReady, + v1alpha1.ServiceConditionRoutesReady, +) + +// TestRouteNotReady tests the scenario that when route's status is +// Ready == false, the service's RouteReady value should change from +// Unknown to False +func TestRouteNotReady(t *testing.T) { + t.Parallel() + cancel := logstream.Start(t) + defer cancel() + + clients := Setup(t) + + names := test.ResourceNames{ + Service: test.ObjectNameForTest(t), + Image: test.PizzaPlanet1, + } + + test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) + defer test.TearDown(clients, names) + + withTrafficSpec := WithInlineRouteSpec(v1alpha1.RouteSpec{ + Traffic: []v1alpha1.TrafficTarget{ + { + TrafficTarget: v1beta1.TrafficTarget{ + RevisionName: "foobar", // Invalid revision name. This allows Revision creation to succeed and Route configuration to fail + Percent: 100, + }, + }, + }, + }) + + t.Log("Creating a new Service with RouteReady == Unknown and route Ready == False") + svc, err := v1a1test.CreateLatestService(t, clients, names, withTrafficSpec) + if err != nil { + t.Fatalf("Failed to create initial Service %q: %#v", names.Service, err) + } + + t.Logf("Waiting for Service %q to transition to Ready == false.", names.Service) + if err := v1a1test.WaitForServiceState(clients.ServingAlphaClient, names.Service, v1a1test.IsServiceNotReady, "ServiceIsNotReady"); err != nil { + t.Fatalf("Failed waiting for Service %q to transition to Ready false: %#v", names.Service, err) + } + + t.Logf("Waiting for Route %q to transition to Ready == false.", serviceresourcenames.Route(svc)) + // Check Route is not ready + if err = v1a1test.WaitForRouteState(clients.ServingAlphaClient, serviceresourcenames.Route(svc), v1a1test.IsRouteNotReady, "RouteIsNotReady"); err != nil { + t.Fatalf("The Route %s was marked as Ready to serve traffic but it should not be: %#v", names.Route, err) + } + + // Wait for RouteReady to become false + t.Log("Wait for the service RouteReady to be false") + if err = v1a1test.WaitForServiceState(clients.ServingAlphaClient, names.Service, v1a1test.IsServiceNotRouteReady, "ServiceRouteReadyFalse"); err != nil { + t.Fatalf("Service RouteReady is not set to false") + } +} diff --git a/test/v1alpha1/service.go b/test/v1alpha1/service.go index 6752e53bd7e6..864e0e3f8f5c 100644 --- a/test/v1alpha1/service.go +++ b/test/v1alpha1/service.go @@ -33,6 +33,7 @@ import ( "knative.dev/pkg/test/logging" "knative.dev/serving/pkg/apis/serving/v1alpha1" serviceresourcenames "knative.dev/serving/pkg/reconciler/service/resources/names" + corev1 "k8s.io/api/core/v1" ptest "knative.dev/pkg/test" rtesting "knative.dev/serving/pkg/testing/v1alpha1" @@ -346,8 +347,16 @@ func IsServiceReady(s *v1alpha1.Service) (bool, error) { return s.Generation == s.Status.ObservedGeneration && s.Status.IsReady(), nil } -// IsServiceNotReady will check the status conditions of the service and return true if the service is -// not ready. +// IsServiceNotReady will check the status conditions of the service and return false if the service is +// ready. func IsServiceNotReady(s *v1alpha1.Service) (bool, error) { - return s.Generation == s.Status.ObservedGeneration && !s.Status.IsReady(), nil + result := s.Status.GetCondition(v1alpha1.ServiceConditionReady) + return result != nil && result.Status == corev1.ConditionFalse, nil +} + +// IsServiceNotRouteReady checks the RouteReady status of the service and return false if the service's +// RouteReady is true. +func IsServiceNotRouteReady(s *v1alpha1.Service) (bool, error) { + result := s.Status.GetCondition(v1alpha1.ServiceConditionRoutesReady) + return result != nil && result.Status == corev1.ConditionFalse, nil } From 979204d3a73f4ba091eb6b6dbe6ccb038f23ae5b Mon Sep 17 00:00:00 2001 From: Tara Gu Date: Thu, 18 Jul 2019 20:18:59 -0400 Subject: [PATCH 2/2] Address review comments --- test/e2e/route_service_test.go | 32 +++++++++++++------------------- test/v1alpha1/service.go | 12 +++++------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/test/e2e/route_service_test.go b/test/e2e/route_service_test.go index 9838c93215c1..84c094473c53 100644 --- a/test/e2e/route_service_test.go +++ b/test/e2e/route_service_test.go @@ -26,20 +26,14 @@ import ( "knative.dev/serving/test" v1a1test "knative.dev/serving/test/v1alpha1" "knative.dev/pkg/test/logstream" - "knative.dev/pkg/apis" serviceresourcenames "knative.dev/serving/pkg/reconciler/service/resources/names" . "knative.dev/serving/pkg/testing/v1alpha1" ) -var serviceCondSet = apis.NewLivingConditionSet( - v1alpha1.ServiceConditionConfigurationsReady, - v1alpha1.ServiceConditionRoutesReady, -) - -// TestRouteNotReady tests the scenario that when route's status is -// Ready == false, the service's RouteReady value should change from +// TestRoutesNotReady tests the scenario that when Route's status is +// Ready == False, the Service's RoutesReady value should change from // Unknown to False -func TestRouteNotReady(t *testing.T) { +func TestRoutesNotReady(t *testing.T) { t.Parallel() cancel := logstream.Start(t) defer cancel() @@ -65,26 +59,26 @@ func TestRouteNotReady(t *testing.T) { }, }) - t.Log("Creating a new Service with RouteReady == Unknown and route Ready == False") + t.Log("Creating a new Service with an invalid traffic target.") svc, err := v1a1test.CreateLatestService(t, clients, names, withTrafficSpec) if err != nil { t.Fatalf("Failed to create initial Service %q: %#v", names.Service, err) } - t.Logf("Waiting for Service %q to transition to Ready == false.", names.Service) + t.Logf("Waiting for Service %q ObservedGeneration to match Generation, and status transition to Ready == False.", names.Service) if err := v1a1test.WaitForServiceState(clients.ServingAlphaClient, names.Service, v1a1test.IsServiceNotReady, "ServiceIsNotReady"); err != nil { - t.Fatalf("Failed waiting for Service %q to transition to Ready false: %#v", names.Service, err) + t.Fatalf("Failed waiting for Service %q to transition to Ready == False: %#v", names.Service, err) } - t.Logf("Waiting for Route %q to transition to Ready == false.", serviceresourcenames.Route(svc)) + t.Logf("Validating Route %q has reconciled to Ready == False.", serviceresourcenames.Route(svc)) // Check Route is not ready - if err = v1a1test.WaitForRouteState(clients.ServingAlphaClient, serviceresourcenames.Route(svc), v1a1test.IsRouteNotReady, "RouteIsNotReady"); err != nil { - t.Fatalf("The Route %s was marked as Ready to serve traffic but it should not be: %#v", names.Route, err) + if err = v1a1test.CheckRouteState(clients.ServingAlphaClient, serviceresourcenames.Route(svc), v1a1test.IsRouteNotReady); err != nil { + t.Fatalf("The Route %q was marked as Ready to serve traffic but it should not be: %#v", serviceresourcenames.Route(svc), err) } - // Wait for RouteReady to become false - t.Log("Wait for the service RouteReady to be false") - if err = v1a1test.WaitForServiceState(clients.ServingAlphaClient, names.Service, v1a1test.IsServiceNotRouteReady, "ServiceRouteReadyFalse"); err != nil { - t.Fatalf("Service RouteReady is not set to false") + // Wait for RoutesReady to become False + t.Logf("Validating Service %q has reconciled to RoutesReady == False.", names.Service) + if err = v1a1test.CheckServiceState(clients.ServingAlphaClient, names.Service, v1a1test.IsServiceRoutesNotReady); err != nil { + t.Fatalf("Service %q was not marked RoutesReady == False: %#v", names.Service, err) } } diff --git a/test/v1alpha1/service.go b/test/v1alpha1/service.go index 864e0e3f8f5c..ec2999f79502 100644 --- a/test/v1alpha1/service.go +++ b/test/v1alpha1/service.go @@ -347,16 +347,14 @@ func IsServiceReady(s *v1alpha1.Service) (bool, error) { return s.Generation == s.Status.ObservedGeneration && s.Status.IsReady(), nil } -// IsServiceNotReady will check the status conditions of the service and return false if the service is -// ready. +// IsServiceNotReady checks the Ready status condition of the service and returns true only if Ready is set to False. func IsServiceNotReady(s *v1alpha1.Service) (bool, error) { result := s.Status.GetCondition(v1alpha1.ServiceConditionReady) - return result != nil && result.Status == corev1.ConditionFalse, nil + return s.Generation == s.Status.ObservedGeneration && result != nil && result.Status == corev1.ConditionFalse, nil } -// IsServiceNotRouteReady checks the RouteReady status of the service and return false if the service's -// RouteReady is true. -func IsServiceNotRouteReady(s *v1alpha1.Service) (bool, error) { +// IsServiceRoutesNotReady checks the RoutesReady status of the service and returns true only if RoutesReady is set to False. +func IsServiceRoutesNotReady(s *v1alpha1.Service) (bool, error) { result := s.Status.GetCondition(v1alpha1.ServiceConditionRoutesReady) - return result != nil && result.Status == corev1.ConditionFalse, nil + return s.Generation == s.Status.ObservedGeneration && result != nil && result.Status == corev1.ConditionFalse, nil }