This is an automated email from the ASF dual-hosted git repository.

zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 2a73216  fix: verify generation in record status (#706)
2a73216 is described below

commit 2a732167c9e1b47a80f4b1fc89b4623bf669332e
Author: kv <[email protected]>
AuthorDate: Wed Oct 27 00:49:37 2021 +0800

    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(-)

diff --git a/pkg/ingress/apisix_cluster_config.go 
b/pkg/ingress/apisix_cluster_config.go
index 835203b..ea2146c 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 0cf28ba..28ce7e3 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 e7de855..d1af33a 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 79c9478..a289b31 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 481eb1c..f2e6261 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 6104728..839fba3 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 bf0d075..f19873e 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 63ad7a3..2be7791 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 0000000..fcf9060
--- /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 2c6b3fd..8761980 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)

Reply via email to