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

tokers 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 7b67cda  feat: add event & status for ApisixRoute v2 (#386)
7b67cda is described below

commit 7b67cdadfa4cb718dd02d00a31f6e19f728a5506
Author: kv <[email protected]>
AuthorDate: Fri Apr 23 14:02:43 2021 +0800

    feat: add event & status for ApisixRoute v2 (#386)
---
 go.sum                                             |  1 +
 pkg/ingress/apisix_route.go                        | 52 ++++++++++++++++++++--
 pkg/ingress/apisix_tls.go                          |  6 ++-
 pkg/ingress/apisix_upstream.go                     |  9 +++-
 pkg/ingress/controller.go                          | 35 +++++++++++++++
 pkg/ingress/endpoint.go                            |  2 +-
 pkg/ingress/secret.go                              |  2 +-
 pkg/ingress/status.go                              | 52 ++++++++++++++++++++++
 pkg/kube/apisix/apis/config/v2alpha1/types.go      | 11 +++--
 .../apis/config/v2alpha1/zz_generated.deepcopy.go  | 29 ++++++++++++
 .../versioned/typed/config/v2alpha1/apisixroute.go | 17 +++++++
 .../typed/config/v2alpha1/fake/fake_apisixroute.go | 12 +++++
 samples/deploy/crd/v1beta1/ApisixRoute.yaml        |  2 +
 test/e2e/endpoints/endpoints.go                    |  5 ++-
 14 files changed, 222 insertions(+), 13 deletions(-)

diff --git a/go.sum b/go.sum
index 93e363c..bf96455 100644
--- a/go.sum
+++ b/go.sum
@@ -623,6 +623,7 @@ k8s.io/api v0.20.2 
h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw=
 k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8=
 k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg=
 k8s.io/apimachinery v0.20.2/go.mod 
h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA=
 k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ=
 k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE=
 k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod 
h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
diff --git a/pkg/ingress/apisix_route.go b/pkg/ingress/apisix_route.go
index fd4ad5a..b91c8b7 100644
--- a/pkg/ingress/apisix_route.go
+++ b/pkg/ingress/apisix_route.go
@@ -19,7 +19,9 @@ import (
        "time"
 
        "go.uber.org/zap"
+       v1 "k8s.io/api/core/v1"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/client-go/tools/cache"
        "k8s.io/client-go/util/workqueue"
 
@@ -184,6 +186,7 @@ func (c *apisixRouteController) sync(ctx context.Context, 
ev *types.Event) error
                                zap.Error(err),
                                zap.Any("ApisixRoute", ar),
                        )
+
                        return err
                }
 
@@ -197,15 +200,58 @@ func (c *apisixRouteController) sync(ctx context.Context, 
ev *types.Event) error
        return c.controller.syncManifests(ctx, added, updated, deleted)
 }
 
-func (c *apisixRouteController) handleSyncErr(obj interface{}, err error) {
-       if err == nil {
+func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin 
error) {
+       ev := obj.(*types.Event)
+       event := ev.Object.(kube.ApisixRouteEvent)
+       namespace, name, errLocal := cache.SplitMetaNamespaceKey(event.Key)
+       if errLocal != nil {
+               log.Errorf("invalid resource key: %s", event.Key)
+               return
+       }
+       var ar kube.ApisixRoute
+       if event.GroupVersion == kube.ApisixRouteV1 {
+               ar, errLocal = c.controller.apisixRouteLister.V1(namespace, 
name)
+       } else {
+               ar, errLocal = 
c.controller.apisixRouteLister.V2alpha1(namespace, name)
+       }
+       if errOrigin == nil {
+               if ev.Type != types.EventDelete {
+                       if errLocal == nil {
+                               if ar.GroupVersion() == kube.ApisixRouteV1 {
+                                       c.controller.recorderEvent(ar.V1(), 
v1.EventTypeNormal, _resourceSynced, nil)
+                               } else if ar.GroupVersion() == 
kube.ApisixRouteV2alpha1 {
+                                       
c.controller.recorderEvent(ar.V2alpha1(), v1.EventTypeNormal, _resourceSynced, 
nil)
+                                       recordRouteStatus(ar.V2alpha1(), 
_resourceSynced, _commonSuccessMessage, metav1.ConditionTrue)
+                               }
+                       } else {
+                               log.Errorw("failed list ApisixRoute",
+                                       zap.Error(errLocal),
+                                       zap.String("name", name),
+                                       zap.String("namespace", namespace),
+                               )
+                       }
+               }
                c.workqueue.Forget(obj)
                return
        }
        log.Warnw("sync ApisixRoute failed, will retry",
                zap.Any("object", obj),
-               zap.Error(err),
+               zap.Error(errOrigin),
        )
+       if errLocal == nil {
+               if ar.GroupVersion() == kube.ApisixRouteV1 {
+                       c.controller.recorderEvent(ar.V1(), 
v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
+               } else if ar.GroupVersion() == kube.ApisixRouteV2alpha1 {
+                       c.controller.recorderEvent(ar.V2alpha1(), 
v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
+                       recordRouteStatus(ar.V2alpha1(), _resourceSyncAborted, 
errOrigin.Error(), metav1.ConditionFalse)
+               }
+       } else {
+               log.Errorw("failed list ApisixRoute",
+                       zap.Error(errLocal),
+                       zap.String("name", name),
+                       zap.String("namespace", namespace),
+               )
+       }
        c.workqueue.AddRateLimited(obj)
 }
 
diff --git a/pkg/ingress/apisix_tls.go b/pkg/ingress/apisix_tls.go
index 4e439df..92330a3 100644
--- a/pkg/ingress/apisix_tls.go
+++ b/pkg/ingress/apisix_tls.go
@@ -20,6 +20,7 @@ import (
        "time"
 
        "go.uber.org/zap"
+       corev1 "k8s.io/api/core/v1"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/client-go/tools/cache"
        "k8s.io/client-go/util/workqueue"
@@ -42,7 +43,6 @@ func (c *Controller) newApisixTlsController() 
*apisixTlsController {
                workqueue:  
workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second,
 60*time.Second, 5), "ApisixTls"),
                workers:    1,
        }
-
        ctl.controller.apisixTlsInformer.AddEventHandler(
                cache.ResourceEventHandlerFuncs{
                        AddFunc:    ctl.onAdd,
@@ -117,6 +117,7 @@ func (c *apisixTlsController) sync(ctx context.Context, ev 
*types.Event) error {
                        zap.Error(err),
                        zap.Any("ApisixTls", tls),
                )
+               c.controller.recorderEvent(tls, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
                return err
        }
        log.Debug("got SSL object from ApisixTls",
@@ -132,8 +133,11 @@ func (c *apisixTlsController) sync(ctx context.Context, ev 
*types.Event) error {
                        zap.Error(err),
                        zap.Any("ssl", ssl),
                )
+               c.controller.recorderEvent(tls, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
                return err
        }
+
+       c.controller.recorderEvent(tls, corev1.EventTypeNormal, 
_resourceSynced, nil)
        return err
 }
 
diff --git a/pkg/ingress/apisix_upstream.go b/pkg/ingress/apisix_upstream.go
index 28b2c9f..7a2d591 100644
--- a/pkg/ingress/apisix_upstream.go
+++ b/pkg/ingress/apisix_upstream.go
@@ -19,6 +19,7 @@ import (
        "time"
 
        "go.uber.org/zap"
+       corev1 "k8s.io/api/core/v1"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/client-go/tools/cache"
        "k8s.io/client-go/util/workqueue"
@@ -42,7 +43,6 @@ func (c *Controller) newApisixUpstreamController() 
*apisixUpstreamController {
                workqueue:  
workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second,
 60*time.Second, 5), "ApisixUpstream"),
                workers:    1,
        }
-
        ctl.controller.apisixUpstreamInformer.AddEventHandler(
                cache.ResourceEventHandlerFuncs{
                        AddFunc:    ctl.onAdd,
@@ -122,6 +122,7 @@ func (c *apisixUpstreamController) sync(ctx 
context.Context, ev *types.Event) er
        svc, err := c.controller.svcLister.Services(namespace).Get(name)
        if err != nil {
                log.Errorf("failed to get service %s: %s", key, err)
+               c.controller.recorderEvent(au, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
                return err
        }
 
@@ -134,6 +135,7 @@ func (c *apisixUpstreamController) sync(ctx 
context.Context, ev *types.Event) er
                                continue
                        }
                        log.Errorf("failed to get upstream %s: %s", upsName, 
err)
+                       c.controller.recorderEvent(au, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
                        return err
                }
                var newUps *apisixv1.Upstream
@@ -149,6 +151,7 @@ func (c *apisixUpstreamController) sync(ctx 
context.Context, ev *types.Event) er
                                        zap.Any("object", au),
                                        zap.Error(err),
                                )
+                               c.controller.recorderEvent(au, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
                                return err
                        }
                } else {
@@ -168,10 +171,12 @@ func (c *apisixUpstreamController) sync(ctx 
context.Context, ev *types.Event) er
                                zap.Any("upstream", newUps),
                                zap.Any("ApisixUpstream", au),
                        )
+                       c.controller.recorderEvent(au, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
                        return err
                }
        }
-       return nil
+       c.controller.recorderEvent(au, corev1.EventTypeNormal, _resourceSynced, 
nil)
+       return err
 }
 
 func (c *apisixUpstreamController) handleSyncErr(obj interface{}, err error) {
diff --git a/pkg/ingress/controller.go b/pkg/ingress/controller.go
index a29cbbb..89876e2 100644
--- a/pkg/ingress/controller.go
+++ b/pkg/ingress/controller.go
@@ -16,6 +16,7 @@ package ingress
 
 import (
        "context"
+       "fmt"
        "os"
        "sync"
        "time"
@@ -25,10 +26,13 @@ import (
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/kubernetes/scheme"
+       typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
        listerscorev1 "k8s.io/client-go/listers/core/v1"
        "k8s.io/client-go/tools/cache"
        "k8s.io/client-go/tools/leaderelection"
        "k8s.io/client-go/tools/leaderelection/resourcelock"
+       "k8s.io/client-go/tools/record"
 
        "github.com/apache/apisix-ingress-controller/pkg/api"
        "github.com/apache/apisix-ingress-controller/pkg/apisix"
@@ -44,6 +48,19 @@ import (
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
+const (
+       // _component is used for event component
+       _component = "ApisixIngress"
+       // _resourceSynced is used when a resource is synced successfully
+       _resourceSynced = "ResourcesSynced"
+       // _messageResourceSynced is used to specify controller
+       _messageResourceSynced = "%s synced successfully"
+       // _resourceSyncAborted is used when a resource synced failed
+       _resourceSyncAborted = "ResourceSyncAborted"
+       // _messageResourceFailed is used to report error
+       _messageResourceFailed = "%s synced failed, with error: %s"
+)
+
 // Controller is the ingress apisix controller object.
 type Controller struct {
        name               string
@@ -58,6 +75,8 @@ type Controller struct {
        crdClientset       crdclientset.Interface
        metricsCollector   metrics.Collector
        crdInformerFactory externalversions.SharedInformerFactory
+       // recorder event
+       recorder record.EventRecorder
        // this map enrolls which ApisixTls objects refer to a Kubernetes
        // Secret object.
        secretSSLMap *sync.Map
@@ -146,6 +165,10 @@ func NewController(cfg *config.Config) (*Controller, 
error) {
                apisixRouteInformer = 
sharedInformerFactory.Apisix().V1().ApisixRoutes().Informer()
        }
 
+       // recorder
+       eventBroadcaster := record.NewBroadcaster()
+       
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: 
kube.GetKubeClient().CoreV1().Events("")})
+
        c := &Controller{
                name:               podName,
                namespace:          podNamespace,
@@ -158,6 +181,7 @@ func NewController(cfg *config.Config) (*Controller, error) 
{
                crdInformerFactory: sharedInformerFactory,
                watchingNamespace:  watchingNamespace,
                secretSSLMap:       new(sync.Map),
+               recorder:           eventBroadcaster.NewRecorder(scheme.Scheme, 
v1.EventSource{Component: _component}),
 
                epInformer:             
kube.CoreSharedInformerFactory.Core().V1().Endpoints().Informer(),
                epLister:               
kube.CoreSharedInformerFactory.Core().V1().Endpoints().Lister(),
@@ -191,6 +215,17 @@ func NewController(cfg *config.Config) (*Controller, 
error) {
        return c, nil
 }
 
+// recorderEvent recorder events for resources
+func (c *Controller) recorderEvent(object runtime.Object, eventtype, reason 
string, err error) {
+       if err != nil {
+               message := fmt.Sprintf(_messageResourceFailed, _component, 
err.Error())
+               c.recorder.Event(object, eventtype, reason, message)
+       } else {
+               message := fmt.Sprintf(_messageResourceSynced, _component)
+               c.recorder.Event(object, eventtype, reason, message)
+       }
+}
+
 func (c *Controller) goAttach(handler func()) {
        c.wg.Add(1)
        go func() {
diff --git a/pkg/ingress/endpoint.go b/pkg/ingress/endpoint.go
index 42c2e63..6514d91 100644
--- a/pkg/ingress/endpoint.go
+++ b/pkg/ingress/endpoint.go
@@ -181,7 +181,7 @@ func (c *endpointsController) onAdd(obj interface{}) {
                return
        }
        log.Debugw("endpoints add event arrived",
-               zap.Any("object", obj))
+               zap.String("object-key", key))
 
        c.workqueue.AddRateLimited(&types.Event{
                Type:   types.EventAdd,
diff --git a/pkg/ingress/secret.go b/pkg/ingress/secret.go
index d831d33..143eddc 100644
--- a/pkg/ingress/secret.go
+++ b/pkg/ingress/secret.go
@@ -185,7 +185,7 @@ func (c *secretController) onAdd(obj interface{}) {
        }
 
        log.Debugw("secret add event arrived",
-               zap.Any("object", obj),
+               zap.String("object-key", key),
        )
        c.workqueue.AddRateLimited(&types.Event{
                Type:   types.EventAdd,
diff --git a/pkg/ingress/status.go b/pkg/ingress/status.go
new file mode 100644
index 0000000..4757db1
--- /dev/null
+++ b/pkg/ingress/status.go
@@ -0,0 +1,52 @@
+// 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 (
+       "context"
+
+       "k8s.io/apimachinery/pkg/api/meta"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+       "github.com/apache/apisix-ingress-controller/pkg/kube"
+       configv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+)
+
+const (
+       _conditionType        = "ResourcesAvailable"
+       _commonSuccessMessage = "Sync Successfully"
+)
+
+// recordRouteStatus record ApisixRoute v2alpha1 status
+func recordRouteStatus(ar *configv2alpha1.ApisixRoute, reason, message string, 
status v1.ConditionStatus) {
+       // build condition
+       condition := metav1.Condition{
+               Type:    _conditionType,
+               Reason:  reason,
+               Status:  status,
+               Message: message,
+       }
+
+       // set to status
+       if ar.Status.Conditions == nil {
+               conditions := make([]metav1.Condition, 0)
+               ar.Status.Conditions = &conditions
+       }
+       meta.SetStatusCondition(ar.Status.Conditions, condition)
+       _, _ = 
kube.GetApisixClient().ApisixV2alpha1().ApisixRoutes(ar.Namespace).
+               UpdateStatus(context.TODO(), ar, metav1.UpdateOptions{})
+}
diff --git a/pkg/kube/apisix/apis/config/v2alpha1/types.go 
b/pkg/kube/apisix/apis/config/v2alpha1/types.go
index 3d1bb72..926addb 100644
--- a/pkg/kube/apisix/apis/config/v2alpha1/types.go
+++ b/pkg/kube/apisix/apis/config/v2alpha1/types.go
@@ -21,9 +21,6 @@ import (
        "k8s.io/apimachinery/pkg/util/intstr"
 )
 
-// +genclient
-// +genclient:noStatus
-
 const (
        // OpEqual means the equal ("==") operator in nginxVars.
        OpEqual = "Equal"
@@ -60,12 +57,20 @@ const (
        ScopeCookie = "Cookie"
 )
 
+// +genclient
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+// +kubebuilder:subresource:status
 // ApisixRoute is used to define the route rules and upstreams for Apache 
APISIX.
 type ApisixRoute struct {
        metav1.TypeMeta   `json:",inline" yaml:",inline"`
        metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
        Spec              *ApisixRouteSpec `json:"spec,omitempty" 
yaml:"spec,omitempty"`
+       Status            ApisixStatus     `json:"status,omitempty" 
yaml:"status,omitempty"`
+}
+
+// ApisixStatus is the status report for Apisix ingress Resources
+type ApisixStatus struct {
+       Conditions *[]metav1.Condition `json:"conditions,omitempty" 
yaml:"conditions,omitempty"`
 }
 
 // ApisixRouteSpec is the spec definition for ApisixRouteSpec.
diff --git a/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go 
b/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go
index f35d721..16cedce 100644
--- a/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go
+++ b/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go
@@ -21,6 +21,7 @@ limitations under the License.
 package v2alpha1
 
 import (
+       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
@@ -34,6 +35,7 @@ func (in *ApisixRoute) DeepCopyInto(out *ApisixRoute) {
                *out = new(ApisixRouteSpec)
                (*in).DeepCopyInto(*out)
        }
+       in.Status.DeepCopyInto(&out.Status)
        return
 }
 
@@ -349,3 +351,30 @@ func (in *ApisixRouteTCPMatch) DeepCopy() 
*ApisixRouteTCPMatch {
        in.DeepCopyInto(out)
        return out
 }
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixStatus) DeepCopyInto(out *ApisixStatus) {
+       *out = *in
+       if in.Conditions != nil {
+               in, out := &in.Conditions, &out.Conditions
+               *out = new([]v1.Condition)
+               if **in != nil {
+                       in, out := *in, *out
+                       *out = make([]v1.Condition, len(*in))
+                       for i := range *in {
+                               (*in)[i].DeepCopyInto(&(*out)[i])
+                       }
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixStatus.
+func (in *ApisixStatus) DeepCopy() *ApisixStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixStatus)
+       in.DeepCopyInto(out)
+       return out
+}
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixroute.go
 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixroute.go
index 91a26c4..2b291b7 100644
--- 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixroute.go
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixroute.go
@@ -40,6 +40,7 @@ type ApisixRoutesGetter interface {
 type ApisixRouteInterface interface {
        Create(ctx context.Context, apisixRoute *v2alpha1.ApisixRoute, opts 
v1.CreateOptions) (*v2alpha1.ApisixRoute, error)
        Update(ctx context.Context, apisixRoute *v2alpha1.ApisixRoute, opts 
v1.UpdateOptions) (*v2alpha1.ApisixRoute, error)
+       UpdateStatus(ctx context.Context, apisixRoute *v2alpha1.ApisixRoute, 
opts v1.UpdateOptions) (*v2alpha1.ApisixRoute, error)
        Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
        DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts 
v1.ListOptions) error
        Get(ctx context.Context, name string, opts v1.GetOptions) 
(*v2alpha1.ApisixRoute, error)
@@ -135,6 +136,22 @@ func (c *apisixRoutes) Update(ctx context.Context, 
apisixRoute *v2alpha1.ApisixR
        return
 }
 
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating 
UpdateStatus().
+func (c *apisixRoutes) UpdateStatus(ctx context.Context, apisixRoute 
*v2alpha1.ApisixRoute, opts v1.UpdateOptions) (result *v2alpha1.ApisixRoute, 
err error) {
+       result = &v2alpha1.ApisixRoute{}
+       err = c.client.Put().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               Name(apisixRoute.Name).
+               SubResource("status").
+               VersionedParams(&opts, scheme.ParameterCodec).
+               Body(apisixRoute).
+               Do(ctx).
+               Into(result)
+       return
+}
+
 // Delete takes name of the apisixRoute and deletes it. Returns an error if 
one occurs.
 func (c *apisixRoutes) Delete(ctx context.Context, name string, opts 
v1.DeleteOptions) error {
        return c.client.Delete().
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixroute.go
 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixroute.go
index a57673b..f2d0a26 100644
--- 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixroute.go
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixroute.go
@@ -102,6 +102,18 @@ func (c *FakeApisixRoutes) Update(ctx context.Context, 
apisixRoute *v2alpha1.Api
        return obj.(*v2alpha1.ApisixRoute), err
 }
 
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating 
UpdateStatus().
+func (c *FakeApisixRoutes) UpdateStatus(ctx context.Context, apisixRoute 
*v2alpha1.ApisixRoute, opts v1.UpdateOptions) (*v2alpha1.ApisixRoute, error) {
+       obj, err := c.Fake.
+               
Invokes(testing.NewUpdateSubresourceAction(apisixroutesResource, "status", 
c.ns, apisixRoute), &v2alpha1.ApisixRoute{})
+
+       if obj == nil {
+               return nil, err
+       }
+       return obj.(*v2alpha1.ApisixRoute), err
+}
+
 // Delete takes name of the apisixRoute and deletes it. Returns an error if 
one occurs.
 func (c *FakeApisixRoutes) Delete(ctx context.Context, name string, opts 
v1.DeleteOptions) error {
        _, err := c.Fake.
diff --git a/samples/deploy/crd/v1beta1/ApisixRoute.yaml 
b/samples/deploy/crd/v1beta1/ApisixRoute.yaml
index 2157a51..d335379 100644
--- a/samples/deploy/crd/v1beta1/ApisixRoute.yaml
+++ b/samples/deploy/crd/v1beta1/ApisixRoute.yaml
@@ -49,6 +49,8 @@ spec:
     shortNames:
       - ar
   preserveUnknownFields: true # we have to enable it since plugin config
+  subresources:
+    status: {}
   validation:
     openAPIV3Schema:
       type: object
diff --git a/test/e2e/endpoints/endpoints.go b/test/e2e/endpoints/endpoints.go
index 8cc2c4f..0973a05 100644
--- a/test/e2e/endpoints/endpoints.go
+++ b/test/e2e/endpoints/endpoints.go
@@ -19,9 +19,10 @@ import (
        "net/http"
        "time"
 
-       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
        "github.com/onsi/ginkgo"
        "github.com/stretchr/testify/assert"
+
+       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
 )
 
 var _ = ginkgo.Describe("endpoints", func() {
@@ -116,7 +117,7 @@ spec:
 
                // scale HTTPBIN, so the endpoints controller has the 
opportunity to update upstream.
                assert.Nil(ginkgo.GinkgoT(), s.ScaleHTTPBIN(3))
-               time.Sleep(10 * time.Second)
+               time.Sleep(15 * time.Second)
                ups, err = s.ListApisixUpstreams()
                assert.Nil(ginkgo.GinkgoT(), err, "listing APISIX upstreams")
                assert.Len(ginkgo.GinkgoT(), ups, 1)

Reply via email to