From 2a732167c9e1b47a80f4b1fc89b4623bf669332e Mon Sep 17 00:00:00 2001 From: kv Date: Wed, 27 Oct 2021 00:49:37 +0800 Subject: [PATCH] fix: verify generation in record status (#706) --- pkg/ingress/apisix_cluster_config.go | 8 +- pkg/ingress/apisix_consumer.go | 4 +- pkg/ingress/apisix_route.go | 12 +-- pkg/ingress/apisix_tls.go | 6 +- pkg/ingress/apisix_upstream.go | 10 +- pkg/ingress/secret.go | 8 +- pkg/ingress/status.go | 128 +++++++++++++++---------- samples/deploy/crd/v1/ApisixRoute.yaml | 72 ++++++++++++++ test/e2e/ingress/status.go | 71 ++++++++++++++ test/e2e/scaffold/k8s.go | 8 ++ 10 files changed, 250 insertions(+), 77 deletions(-) create mode 100644 test/e2e/ingress/status.go diff --git a/pkg/ingress/apisix_cluster_config.go b/pkg/ingress/apisix_cluster_config.go index 835203b68f..ea2146c05e 100644 --- a/pkg/ingress/apisix_cluster_config.go +++ b/pkg/ingress/apisix_cluster_config.go @@ -143,7 +143,7 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even zap.Any("opts", clusterOpts), ) c.controller.recorderEvent(acc, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(acc, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(acc, _resourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration()) return err } } @@ -157,7 +157,7 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even zap.Any("object", acc), ) c.controller.recorderEvent(acc, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(acc, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(acc, _resourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration()) return err } log.Debugw("translated global_rule", @@ -176,11 +176,11 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even zap.Any("cluster", acc.Name), ) c.controller.recorderEvent(acc, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(acc, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(acc, _resourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration()) return err } c.controller.recorderEvent(acc, corev1.EventTypeNormal, _resourceSynced, nil) - c.controller.recordStatus(acc, _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(acc, _resourceSynced, nil, metav1.ConditionTrue, acc.GetGeneration()) return nil } diff --git a/pkg/ingress/apisix_consumer.go b/pkg/ingress/apisix_consumer.go index 0cf28ba5cf..28ce7e3360 100644 --- a/pkg/ingress/apisix_consumer.go +++ b/pkg/ingress/apisix_consumer.go @@ -116,7 +116,7 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er zap.Any("ApisixConsumer", ac), ) c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration()) return err } log.Debug("got consumer object from ApisixConsumer", @@ -130,7 +130,7 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er zap.Any("consumer", consumer), ) c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration()) c.controller.metricsCollector.IncrSyncOperation("consumer", "failure") return err } diff --git a/pkg/ingress/apisix_route.go b/pkg/ingress/apisix_route.go index e7de855aa4..d1af33ad1b 100644 --- a/pkg/ingress/apisix_route.go +++ b/pkg/ingress/apisix_route.go @@ -270,13 +270,13 @@ func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin error) c.controller.recorderEvent(ar.V1(), v1.EventTypeNormal, _resourceSynced, nil) case kube.ApisixRouteV2alpha1: c.controller.recorderEvent(ar.V2alpha1(), v1.EventTypeNormal, _resourceSynced, nil) - c.controller.recordStatus(ar.V2alpha1(), _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(ar.V2alpha1(), _resourceSynced, nil, metav1.ConditionTrue, ar.V2alpha1().GetGeneration()) case kube.ApisixRouteV2beta1: c.controller.recorderEvent(ar.V2beta1(), v1.EventTypeNormal, _resourceSynced, nil) - c.controller.recordStatus(ar.V2beta1(), _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(ar.V2beta1(), _resourceSynced, nil, metav1.ConditionTrue, ar.V2beta1().GetGeneration()) case kube.ApisixRouteV2beta2: c.controller.recorderEvent(ar.V2beta2(), v1.EventTypeNormal, _resourceSynced, nil) - c.controller.recordStatus(ar.V2beta2(), _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(ar.V2beta2(), _resourceSynced, nil, metav1.ConditionTrue, ar.V2beta2().GetGeneration()) } } else { log.Errorw("failed list ApisixRoute", @@ -299,13 +299,13 @@ func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin error) c.controller.recorderEvent(ar.V1(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin) case kube.ApisixRouteV2alpha1: c.controller.recorderEvent(ar.V2alpha1(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin) - c.controller.recordStatus(ar.V2alpha1(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse) + c.controller.recordStatus(ar.V2alpha1(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2alpha1().GetGeneration()) case kube.ApisixRouteV2beta1: c.controller.recorderEvent(ar.V2beta1(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin) - c.controller.recordStatus(ar.V2beta1(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse) + c.controller.recordStatus(ar.V2beta1(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2beta1().GetGeneration()) case kube.ApisixRouteV2beta2: c.controller.recorderEvent(ar.V2beta2(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin) - c.controller.recordStatus(ar.V2beta2(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse) + c.controller.recordStatus(ar.V2beta2(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2beta2().GetGeneration()) } } else { log.Errorw("failed list ApisixRoute", diff --git a/pkg/ingress/apisix_tls.go b/pkg/ingress/apisix_tls.go index 79c94786fa..a289b31fb5 100644 --- a/pkg/ingress/apisix_tls.go +++ b/pkg/ingress/apisix_tls.go @@ -120,7 +120,7 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error { zap.Any("ApisixTls", tls), ) c.controller.recorderEvent(tls, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration()) return err } log.Debugw("got SSL object from ApisixTls", @@ -143,11 +143,11 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error { zap.Any("ssl", ssl), ) c.controller.recorderEvent(tls, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration()) return err } c.controller.recorderEvent(tls, corev1.EventTypeNormal, _resourceSynced, nil) - c.controller.recordStatus(tls, _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(tls, _resourceSynced, nil, metav1.ConditionTrue, tls.GetGeneration()) return err } diff --git a/pkg/ingress/apisix_upstream.go b/pkg/ingress/apisix_upstream.go index 481eb1ce6a..f2e6261a0f 100644 --- a/pkg/ingress/apisix_upstream.go +++ b/pkg/ingress/apisix_upstream.go @@ -129,7 +129,7 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er if err != nil { log.Errorf("failed to get service %s: %s", key, err) c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration()) return err } @@ -150,7 +150,7 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er } log.Errorf("failed to get upstream %s: %s", upsName, err) c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration()) return err } var newUps *apisixv1.Upstream @@ -167,7 +167,7 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er zap.Error(err), ) c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration()) return err } } else { @@ -189,14 +189,14 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er zap.String("cluster", clusterName), ) c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err) - c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration()) return err } } } if ev.Type != types.EventDelete { c.controller.recorderEvent(au, corev1.EventTypeNormal, _resourceSynced, nil) - c.controller.recordStatus(au, _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(au, _resourceSynced, nil, metav1.ConditionTrue, au.GetGeneration()) } return err } diff --git a/pkg/ingress/secret.go b/pkg/ingress/secret.go index 6104728ca8..839fba368f 100644 --- a/pkg/ingress/secret.go +++ b/pkg/ingress/secret.go @@ -159,7 +159,7 @@ func (c *secretController) sync(ctx context.Context, ev *types.Event) error { go func(tls *configv1.ApisixTls) { c.controller.recorderEventS(tls, corev1.EventTypeWarning, _resourceSyncAborted, fmt.Sprintf("sync from secret %s changes failed, error: %s", key, err.Error())) - c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration()) }(tls) return true } @@ -177,7 +177,7 @@ func (c *secretController) sync(ctx context.Context, ev *types.Event) error { go func(tls *configv1.ApisixTls) { c.controller.recorderEventS(tls, corev1.EventTypeWarning, _resourceSyncAborted, fmt.Sprintf("sync from ca secret %s changes failed, error: %s", key, err.Error())) - c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration()) }(tls) return true } @@ -203,11 +203,11 @@ func (c *secretController) sync(ctx context.Context, ev *types.Event) error { ) c.controller.recorderEventS(tls, corev1.EventTypeWarning, _resourceSyncAborted, fmt.Sprintf("sync from secret %s changes failed, error: %s", key, err.Error())) - c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse) + c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration()) } else { c.controller.recorderEventS(tls, corev1.EventTypeNormal, _resourceSynced, fmt.Sprintf("sync from secret %s changes", key)) - c.controller.recordStatus(tls, _resourceSynced, nil, metav1.ConditionTrue) + c.controller.recordStatus(tls, _resourceSynced, nil, metav1.ConditionTrue, tls.GetGeneration()) } }(ssl, tls) return true diff --git a/pkg/ingress/status.go b/pkg/ingress/status.go index bf0d075add..f19873e1ac 100644 --- a/pkg/ingress/status.go +++ b/pkg/ingress/status.go @@ -35,18 +35,28 @@ const ( _commonSuccessMessage = "Sync Successfully" ) +// verifyGeneration verify generation to decide whether to update status +func (c *Controller) verifyGeneration(conditions *[]metav1.Condition, newCondition metav1.Condition) bool { + existingCondition := meta.FindStatusCondition(*conditions, newCondition.Type) + if existingCondition != nil && existingCondition.ObservedGeneration >= newCondition.ObservedGeneration { + return false + } + return true +} + // recordStatus record resources status -func (c *Controller) recordStatus(at interface{}, reason string, err error, status v1.ConditionStatus) { +func (c *Controller) recordStatus(at interface{}, reason string, err error, status v1.ConditionStatus, generation int64) { // build condition message := _commonSuccessMessage if err != nil { message = err.Error() } condition := metav1.Condition{ - Type: _conditionType, - Reason: reason, - Status: status, - Message: message, + Type: _conditionType, + Reason: reason, + Status: status, + Message: message, + ObservedGeneration: generation, } client := c.kubeClient.APISIXClient @@ -57,14 +67,16 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat conditions := make([]metav1.Condition, 0) v.Status.Conditions = &conditions } - meta.SetStatusCondition(v.Status.Conditions, condition) - if _, errRecord := client.ApisixV1().ApisixTlses(v.Namespace). - UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { - log.Errorw("failed to record status change for ApisixTls", - zap.Error(errRecord), - zap.String("name", v.Name), - zap.String("namespace", v.Namespace), - ) + if c.verifyGeneration(v.Status.Conditions, condition) { + meta.SetStatusCondition(v.Status.Conditions, condition) + if _, errRecord := client.ApisixV1().ApisixTlses(v.Namespace). + UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { + log.Errorw("failed to record status change for ApisixTls", + zap.Error(errRecord), + zap.String("name", v.Name), + zap.String("namespace", v.Namespace), + ) + } } case *configv1.ApisixUpstream: // set to status @@ -72,14 +84,16 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat conditions := make([]metav1.Condition, 0) v.Status.Conditions = &conditions } - meta.SetStatusCondition(v.Status.Conditions, condition) - if _, errRecord := client.ApisixV1().ApisixUpstreams(v.Namespace). - UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { - log.Errorw("failed to record status change for ApisixUpstream", - zap.Error(errRecord), - zap.String("name", v.Name), - zap.String("namespace", v.Namespace), - ) + if c.verifyGeneration(v.Status.Conditions, condition) { + meta.SetStatusCondition(v.Status.Conditions, condition) + if _, errRecord := client.ApisixV1().ApisixUpstreams(v.Namespace). + UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { + log.Errorw("failed to record status change for ApisixUpstream", + zap.Error(errRecord), + zap.String("name", v.Name), + zap.String("namespace", v.Namespace), + ) + } } case *configv2alpha1.ApisixRoute: // set to status @@ -87,14 +101,16 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat conditions := make([]metav1.Condition, 0) v.Status.Conditions = &conditions } - meta.SetStatusCondition(v.Status.Conditions, condition) - if _, errRecord := client.ApisixV2alpha1().ApisixRoutes(v.Namespace). - UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { - log.Errorw("failed to record status change for ApisixRoute", - zap.Error(errRecord), - zap.String("name", v.Name), - zap.String("namespace", v.Namespace), - ) + if c.verifyGeneration(v.Status.Conditions, condition) { + meta.SetStatusCondition(v.Status.Conditions, condition) + if _, errRecord := client.ApisixV2alpha1().ApisixRoutes(v.Namespace). + UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { + log.Errorw("failed to record status change for ApisixRoute", + zap.Error(errRecord), + zap.String("name", v.Name), + zap.String("namespace", v.Namespace), + ) + } } case *configv2beta1.ApisixRoute: // set to status @@ -102,14 +118,16 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat conditions := make([]metav1.Condition, 0) v.Status.Conditions = conditions } - meta.SetStatusCondition(&v.Status.Conditions, condition) - if _, errRecord := client.ApisixV2beta1().ApisixRoutes(v.Namespace). - UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { - log.Errorw("failed to record status change for ApisixRoute", - zap.Error(errRecord), - zap.String("name", v.Name), - zap.String("namespace", v.Namespace), - ) + if c.verifyGeneration(&v.Status.Conditions, condition) { + meta.SetStatusCondition(&v.Status.Conditions, condition) + if _, errRecord := client.ApisixV2beta1().ApisixRoutes(v.Namespace). + UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { + log.Errorw("failed to record status change for ApisixRoute", + zap.Error(errRecord), + zap.String("name", v.Name), + zap.String("namespace", v.Namespace), + ) + } } case *configv2beta2.ApisixRoute: // set to status @@ -117,14 +135,16 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat conditions := make([]metav1.Condition, 0) v.Status.Conditions = conditions } - meta.SetStatusCondition(&v.Status.Conditions, condition) - if _, errRecord := client.ApisixV2beta2().ApisixRoutes(v.Namespace). - UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { - log.Errorw("failed to record status change for ApisixRoute", - zap.Error(errRecord), - zap.String("name", v.Name), - zap.String("namespace", v.Namespace), - ) + if c.verifyGeneration(&v.Status.Conditions, condition) { + meta.SetStatusCondition(&v.Status.Conditions, condition) + if _, errRecord := client.ApisixV2beta2().ApisixRoutes(v.Namespace). + UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { + log.Errorw("failed to record status change for ApisixRoute", + zap.Error(errRecord), + zap.String("name", v.Name), + zap.String("namespace", v.Namespace), + ) + } } case *configv2alpha1.ApisixConsumer: // set to status @@ -132,14 +152,16 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat conditions := make([]metav1.Condition, 0) v.Status.Conditions = &conditions } - meta.SetStatusCondition(v.Status.Conditions, condition) - if _, errRecord := client.ApisixV2alpha1().ApisixConsumers(v.Namespace). - UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { - log.Errorw("failed to record status change for ApisixConsumer", - zap.Error(errRecord), - zap.String("name", v.Name), - zap.String("namespace", v.Namespace), - ) + if c.verifyGeneration(v.Status.Conditions, condition) { + meta.SetStatusCondition(v.Status.Conditions, condition) + if _, errRecord := client.ApisixV2alpha1().ApisixConsumers(v.Namespace). + UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil { + log.Errorw("failed to record status change for ApisixConsumer", + zap.Error(errRecord), + zap.String("name", v.Name), + zap.String("namespace", v.Namespace), + ) + } } default: // This should not be executed diff --git a/samples/deploy/crd/v1/ApisixRoute.yaml b/samples/deploy/crd/v1/ApisixRoute.yaml index 63ad7a373d..2be7791b72 100644 --- a/samples/deploy/crd/v1/ApisixRoute.yaml +++ b/samples/deploy/crd/v1/ApisixRoute.yaml @@ -316,6 +316,24 @@ spec: required: - serviceName - servicePort + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + "type": + type: string + reason: + type: string + status: + type: string + message: + type: string + observedGeneration: + type: integer - name: v2alpha1 served: true storage: false @@ -603,6 +621,24 @@ spec: required: - serviceName - servicePort + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + "type": + type: string + reason: + type: string + status: + type: string + message: + type: string + observedGeneration: + type: integer - name: v2beta1 served: true storage: false @@ -890,6 +926,24 @@ spec: required: - serviceName - servicePort + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + "type": + type: string + reason: + type: string + status: + type: string + message: + type: string + observedGeneration: + type: integer - name: v2beta2 served: true storage: true @@ -1115,3 +1169,21 @@ spec: required: - serviceName - servicePort + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + "type": + type: string + reason: + type: string + status: + type: string + message: + type: string + observedGeneration: + type: integer diff --git a/test/e2e/ingress/status.go b/test/e2e/ingress/status.go new file mode 100644 index 0000000000..fcf9060d27 --- /dev/null +++ b/test/e2e/ingress/status.go @@ -0,0 +1,71 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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 ingress + +import ( + "fmt" + "strings" + + "github.com/onsi/ginkgo" + "github.com/stretchr/testify/assert" + + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" +) + +var _ = ginkgo.Describe("Status subresource Testing", func() { + opts := &scaffold.Options{ + Name: "default", + Kubeconfig: scaffold.GetKubeconfig(), + APISIXConfigPath: "testdata/apisix-gw-config.yaml", + IngressAPISIXReplicas: 1, + HTTPBinServicePort: 80, + APISIXRouteVersion: "apisix.apache.org/v2beta2", + } + s := scaffold.NewScaffold(opts) + ginkgo.It("check the status is recorded", func() { + backendSvc, backendSvcPort := s.DefaultHTTPBackend() + apisixRoute := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2beta2 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.com + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d +`, backendSvc, backendSvcPort[0]) + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(apisixRoute)) + + err := s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + err = s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + // status should be recorded as successful + output, err := s.GetOutputFromString("ar", "httpbin-route", "-o", "yaml") + assert.Nil(ginkgo.GinkgoT(), err, "Get output of ApisixRoute resource") + hasType := strings.Contains(output, "type: ResourcesAvailable") + assert.True(ginkgo.GinkgoT(), hasType, "Status is recorded") + hasMsg := strings.Contains(output, "message: Sync Successfully") + assert.True(ginkgo.GinkgoT(), hasMsg, "Status is recorded") + }) +}) diff --git a/test/e2e/scaffold/k8s.go b/test/e2e/scaffold/k8s.go index 2c6b3fdb7f..8761980647 100644 --- a/test/e2e/scaffold/k8s.go +++ b/test/e2e/scaffold/k8s.go @@ -120,6 +120,14 @@ func (s *Scaffold) CreateResourceFromString(yaml string) error { return err } +func (s *Scaffold) GetOutputFromString(shell ...string) (string, error) { + cmdArgs := []string{} + cmdArgs = append(cmdArgs, "get") + cmdArgs = append(cmdArgs, shell...) + output, err := k8s.RunKubectlAndGetOutputE(ginkgo.GinkgoT(), s.kubectlOptions, cmdArgs...) + return output, err +} + // RemoveResourceByString remove resource from a loaded yaml string. func (s *Scaffold) RemoveResourceByString(yaml string) error { err := k8s.KubectlDeleteFromStringE(s.t, s.kubectlOptions, yaml)