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 c65cc23  feat: ApisixRoute v2alpha1 (#262)
c65cc23 is described below

commit c65cc2384a68b3bd17f886ee2c03e72aafea1206
Author: Alex Zhang <[email protected]>
AuthorDate: Wed Mar 3 14:08:06 2021 +0800

    feat: ApisixRoute v2alpha1 (#262)
---
 cmd/ingress/ingress.go                             |   1 +
 conf/config-default.yaml                           |   3 +
 go.mod                                             |   3 +-
 go.sum                                             |  56 ++-
 pkg/config/config.go                               |  30 +-
 pkg/config/config_test.go                          |  13 +-
 pkg/ingress/controller/apisix_route.go             | 420 ++++++++++-----------
 pkg/ingress/controller/apisix_upstream.go          |  10 +-
 pkg/ingress/controller/controller.go               |  34 +-
 pkg/ingress/controller/ingress.go                  |   1 +
 pkg/kube/apisix/apis/config/v2alpha1/doc.go        |  18 +
 pkg/kube/apisix/apis/config/v2alpha1/register.go   |  50 +++
 pkg/kube/apisix/apis/config/v2alpha1/types.go      | 163 ++++++++
 .../apis/config/v2alpha1/zz_generated.deepcopy.go  | 256 +++++++++++++
 .../apisix/client/clientset/versioned/clientset.go |  16 +-
 .../versioned/fake/clientset_generated.go          |   7 +
 .../client/clientset/versioned/fake/register.go    |   2 +
 .../client/clientset/versioned/scheme/register.go  |   2 +
 .../versioned/typed/config/v2alpha1/apisixroute.go | 178 +++++++++
 .../typed/config/v2alpha1/config_client.go         |  89 +++++
 .../versioned/typed/config/v2alpha1/doc.go         |  20 +
 .../versioned/typed/config/v2alpha1/fake/doc.go    |  20 +
 .../typed/config/v2alpha1/fake/fake_apisixroute.go | 130 +++++++
 .../config/v2alpha1/fake/fake_config_client.go     |  40 ++
 .../typed/config/v2alpha1/generated_expansion.go   |  21 ++
 .../informers/externalversions/config/interface.go |   8 +
 .../config/v2alpha1/apisixroute.go                 |  90 +++++
 .../config/{ => v2alpha1}/interface.go             |  19 +-
 .../client/informers/externalversions/generic.go   |   5 +
 .../client/listers/config/v2alpha1/apisixroute.go  |  99 +++++
 .../listers/config/v2alpha1/expansion_generated.go |  27 ++
 pkg/kube/apisix_route.go                           | 175 +++++++++
 pkg/kube/translation/apisix_route.go               | 117 ++++++
 pkg/kube/translation/translator.go                 |   4 +
 pkg/types/apisix/v1/types.go                       |  19 +
 pkg/types/apisix/v1/zz_generated.deepcopy.go       |  10 +
 samples/deploy/crd/v1beta1/ApisixRoute.yaml        |   3 +
 test/e2e/endpoints/endpoints.go                    |   2 +-
 test/e2e/go.mod                                    |   4 +-
 test/e2e/go.sum                                    |  19 +
 test/e2e/ingress/resourcepushing.go                |  48 ++-
 test/e2e/scaffold/ingress.go                       |   4 +-
 test/e2e/scaffold/scaffold.go                      |   6 +
 43 files changed, 1954 insertions(+), 288 deletions(-)

diff --git a/cmd/ingress/ingress.go b/cmd/ingress/ingress.go
index d43f1cd..381024f 100644
--- a/cmd/ingress/ingress.go
+++ b/cmd/ingress/ingress.go
@@ -139,6 +139,7 @@ the apisix cluster and others are created`,
        cmd.PersistentFlags().StringVar(&cfg.Kubernetes.IngressClass, 
"ingress-class", config.IngressClass, "the class of an Ingress object is set 
using the field IngressClassName in Kubernetes clusters version v1.18.0 or 
higher or the annotation \"kubernetes.io/ingress.class\" (deprecated)")
        cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ElectionID, 
"election-id", config.IngressAPISIXLeader, "election id used for campaign the 
controller leader")
        cmd.PersistentFlags().StringVar(&cfg.Kubernetes.IngressVersion, 
"ingress-version", config.IngressNetworkingV1, "the supported ingress api group 
version, can be \"networking/v1beta1\" or \"networking/v1\" (for Kubernetes 
version v1.19.0 or higher)")
+       cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ApisixRouteVersion, 
"apisix-route-version", config.ApisixRouteV2alpha1, "the supported apisixroute 
api group version, can be \"apisix.apache.org/v1\" or 
\"apisix.apache.org/v2alpha1\"")
        cmd.PersistentFlags().StringVar(&cfg.APISIX.BaseURL, "apisix-base-url", 
"", "the base URL for APISIX admin api / manager api")
        cmd.PersistentFlags().StringVar(&cfg.APISIX.AdminKey, 
"apisix-admin-key", "", "admin key used for the authorization of APISIX admin 
api / manager api")
 
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index b5d81da..73d1866 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -51,6 +51,9 @@ kubernetes:
                                        # or "networking/v1" (for Kubernetes 
version v1.19.0 or higher), default
                                        # is "networking/v1".
 
+  apisix_route_version: "apisix.apache.org/v2alpha1" # the supported 
apisixroute api group version, can be
+                                                     # "apisix.apache.org/v1" 
or "apisix.apache.org/v2alpha1",
+                                                     # default is 
"apisix.apache.org/v2alpha1".
 # APISIX related configurations.
 apisix:
   base_url: "http://127.0.0.1:9080/apisix/admin"; # the APISIX admin api / 
manager api
diff --git a/go.mod b/go.mod
index bf3fd6a..aa872d2 100644
--- a/go.mod
+++ b/go.mod
@@ -3,9 +3,10 @@ module github.com/apache/apisix-ingress-controller
 go 1.13
 
 require (
+       github.com/gavv/httpexpect/v2 v2.2.0 // indirect
        github.com/gin-gonic/gin v1.6.3
        github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
-       github.com/gruntwork-io/terratest v0.32.7 // indirect
+       github.com/gruntwork-io/terratest v0.32.8 // indirect
        github.com/hashicorp/go-memdb v1.0.4
        github.com/hashicorp/golang-lru v0.5.3 // indirect
        github.com/imdario/mergo v0.3.11 // indirect
diff --git a/go.sum b/go.sum
index d538905..b8e07c6 100644
--- a/go.sum
+++ b/go.sum
@@ -71,10 +71,16 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod 
h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
 github.com/PuerkitoBio/purell v1.1.1/go.mod 
h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod 
h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod 
h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/agext/levenshtein v1.2.1/go.mod 
h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
+github.com/ajg/form v1.5.1/go.mod 
h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod 
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod 
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod 
h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
+github.com/apparentlymart/go-textseg v1.0.0/go.mod 
h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
+github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod 
h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod 
h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod 
h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod 
h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -156,13 +162,20 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/evanphx/json-patch v4.2.0+incompatible/go.mod 
h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.9.0+incompatible 
h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod 
h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fasthttp/websocket v1.4.2/go.mod 
h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod 
h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU=
+github.com/fatih/structs v1.0.0/go.mod 
h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod 
h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/fsnotify/fsnotify v1.4.7 
h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod 
h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 
h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod 
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/gavv/httpexpect v1.1.3 
h1:fPDU3PBu5fVcSORltSEcpvAoxmCtDB94re8UVL2tCro=
+github.com/gavv/httpexpect v2.0.0+incompatible 
h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
+github.com/gavv/httpexpect/v2 v2.2.0 
h1:0VwaEBmQaNFHX9x591A8Up+8shCwdF/nF0qlRd/nI48=
+github.com/gavv/httpexpect/v2 v2.2.0/go.mod 
h1:lnd0TqJLrP+wkJk3SFwtrpSlOAZQ7HaaIFuOYbgqgUM=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gin-contrib/sse v0.1.0 
h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@@ -204,6 +217,7 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod 
h1:uOYAAleCW8F/7oMFd6aG0GO
 github.com/go-sql-driver/mysql v1.4.1 
h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
 github.com/go-sql-driver/mysql v1.4.1/go.mod 
h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-test/deep v1.0.3/go.mod 
h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/gogo/protobuf v1.1.1/go.mod 
h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod 
h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod 
h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -224,6 +238,7 @@ github.com/golang/mock v1.3.1/go.mod 
h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
 github.com/golang/mock v1.4.0/go.mod 
h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.1/go.mod 
h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.1.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2 
h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
@@ -251,6 +266,8 @@ github.com/google/go-cmp v0.5.0/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
 github.com/google/go-cmp v0.5.2/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-containerregistry 
v0.0.0-20200110202235-f4fb41bf00a3/go.mod 
h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk=
+github.com/google/go-querystring v1.0.0 
h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
+github.com/google/go-querystring v1.0.0/go.mod 
h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod 
h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
 github.com/google/gofuzz v1.0.0/go.mod 
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -277,7 +294,9 @@ github.com/gophercloud/gophercloud v0.1.0/go.mod 
h1:vxM41WHh5uqHVBMZHzuwNOHh8XEo
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod 
h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/mux v1.7.3/go.mod 
h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod 
h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.0.0/go.mod 
h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.0/go.mod 
h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2 
h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod 
h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod 
h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod 
h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@@ -287,8 +306,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod 
h1:vNeuVxBJEsws4ogUvrchl83t
 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod 
h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/gruntwork-io/gruntwork-cli v0.7.0 
h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arnQQLM4RH+CYs=
 github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod 
h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00=
-github.com/gruntwork-io/terratest v0.32.7 
h1:TJF4ZyOviWknlmzgre48JGGoXa20S8Ng0O/sfBfH+Bw=
-github.com/gruntwork-io/terratest v0.32.7/go.mod 
h1:0iy7d56CziX3R4ZUn570HMElr4WgBKoKNa8Hzex7bvo=
+github.com/gruntwork-io/terratest v0.32.8 
h1:ccIRFH+e6zhSB5difg7baJec4FeOZNXpeIFlZZlKW2M=
+github.com/gruntwork-io/terratest v0.32.8/go.mod 
h1:FckR+7ks472IJfSKUPfPvnJfSxV1LKGWGMJ9m/LHegE=
 github.com/hashicorp/consul/api v1.1.0/go.mod 
h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod 
h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0 
h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -316,6 +335,7 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod 
h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.3 
h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
 github.com/hashicorp/golang-lru v0.5.3/go.mod 
h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod 
h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcl/v2 v2.8.2/go.mod 
h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
 github.com/hashicorp/logutils v1.0.0/go.mod 
h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod 
h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod 
h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
@@ -328,6 +348,8 @@ github.com/imdario/mergo v0.3.5/go.mod 
h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
 github.com/imdario/mergo v0.3.7/go.mod 
h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.11 
h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
 github.com/imdario/mergo v0.3.11/go.mod 
h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imkira/go-interpol v1.0.0 
h1:HrmLyvOLJyjR0YofMw8QGdCIuYOs4TJUBDNU5sJC09E=
+github.com/imkira/go-interpol v1.0.0/go.mod 
h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
 github.com/inconshreveable/mousetrap v1.0.0 
h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod 
h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod 
h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
@@ -352,6 +374,10 @@ github.com/k0kubun/colorstring 
v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q
 github.com/kisielk/errcheck v1.1.0/go.mod 
h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod 
h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
 github.com/kisielk/gotool v1.0.0/go.mod 
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.8.2 
h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
+github.com/klauspost/compress v1.8.2/go.mod 
h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/cpuid v1.2.1 
h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
+github.com/klauspost/cpuid v1.2.1/go.mod 
h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod 
h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -363,6 +389,7 @@ github.com/kr/pty v1.1.1/go.mod 
h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod 
h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
 github.com/leodido/go-urn v1.2.0 
h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
 github.com/leodido/go-urn v1.2.0/go.mod 
h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/magiconair/properties v1.8.0/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -372,6 +399,7 @@ github.com/mailru/easyjson 
v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod 
h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.0/go.mod 
h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
 github.com/mattn/go-colorable v0.0.9/go.mod 
h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.2/go.mod 
h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.4 
h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
 github.com/mattn/go-colorable v0.1.4/go.mod 
h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-isatty v0.0.3/go.mod 
h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -395,6 +423,7 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
 github.com/mitchellh/go-homedir v1.1.0 
h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod 
h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod 
h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/gox v0.4.0/go.mod 
h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -480,8 +509,10 @@ github.com/russross/blackfriday/v2 v2.0.1 
h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
 github.com/russross/blackfriday/v2 v2.0.1/go.mod 
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod 
h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/satori/go.uuid v1.2.0/go.mod 
h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod 
h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
 github.com/sclevine/spec v1.2.0/go.mod 
h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod 
h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0/go.mod 
h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod 
h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0 
h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
@@ -503,6 +534,7 @@ github.com/spf13/cobra v1.1.1/go.mod 
h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJ
 github.com/spf13/jwalterweatherman v1.0.0/go.mod 
h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.2/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -530,10 +562,24 @@ github.com/urfave/cli v1.20.0/go.mod 
h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
 github.com/urfave/cli v1.22.1/go.mod 
h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
 github.com/urfave/cli v1.22.2/go.mod 
h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/valyala/bytebufferpool v1.0.0 
h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod 
h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.9.0 
h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw=
+github.com/valyala/fasthttp v1.9.0/go.mod 
h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
+github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod 
h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
 github.com/vdemeester/k8s-pkg-credentialprovider 
v0.0.0-20200107171650-7c61ffa44238/go.mod 
h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod 
h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
 github.com/vmware/govmomi v0.20.3/go.mod 
h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f 
h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod 
h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 
h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod 
h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.1.0 
h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
+github.com/xeipuuv/gojsonschema v1.1.0/go.mod 
h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod 
h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod 
h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 
h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod 
h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
 github.com/yudai/gojsondiff v1.0.0 
h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
 github.com/yudai/gojsondiff v1.0.0/go.mod 
h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
 github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 
h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
@@ -541,6 +587,7 @@ github.com/yudai/golcs 
v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf
 github.com/yudai/pp v2.0.1+incompatible 
h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
 github.com/yudai/pp v2.0.1+incompatible/go.mod 
h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
 github.com/yuin/goldmark v1.1.27/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zclconf/go-cty v1.2.0/go.mod 
h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod 
h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
@@ -565,6 +612,7 @@ golang.org/x/crypto 
v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 
h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -614,6 +662,7 @@ golang.org/x/mod v0.3.0 
h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -675,6 +724,7 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod 
h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -921,6 +971,8 @@ modernc.org/golex v1.0.0/go.mod 
h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod 
h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
 modernc.org/strutil v1.0.0/go.mod 
h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
 modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
+moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e 
h1:C7q+e9M5nggAvWfVg9Nl66kebKeuJlP3FD58V4RR5wo=
+moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod 
h1:nejbQVfXh96n9dSF6cH3Jsk/QI1Z2oEL7sSI2ifXFNA=
 rsc.io/binaryregexp v0.2.0/go.mod 
h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 46d413c..bb575d8 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -42,6 +42,10 @@ const (
        IngressNetworkingV1 = "networking/v1"
        // IngressNetworkingV1beta1 represents ingress.networking/v1beta1
        IngressNetworkingV1beta1 = "networking/v1beta1"
+       // ApisixRouteV1 represents apisixroute.apisix.apache.org/v1
+       ApisixRouteV1 = "apisix.apache.org/v1"
+       // ApisixRouteV2alpha1 represents apisixroute.apisix.apache.org/v2alpha1
+       ApisixRouteV2alpha1 = "apisix.apache.org/v2alpha1"
 
        _minimalResyncInterval = 30 * time.Second
 )
@@ -59,12 +63,13 @@ type Config struct {
 
 // KubernetesConfig contains all Kubernetes related config items.
 type KubernetesConfig struct {
-       Kubeconfig     string             `json:"kubeconfig" yaml:"kubeconfig"`
-       ResyncInterval types.TimeDuration `json:"resync_interval" 
yaml:"resync_interval"`
-       AppNamespaces  []string           `json:"app_namespaces" 
yaml:"app_namespaces"`
-       ElectionID     string             `json:"election_id" 
yaml:"election_id"`
-       IngressClass   string             `json:"ingress_class" 
yaml:"ingress_class"`
-       IngressVersion string             `json:"ingress_version" 
yaml:"ingress_version"`
+       Kubeconfig         string             `json:"kubeconfig" 
yaml:"kubeconfig"`
+       ResyncInterval     types.TimeDuration `json:"resync_interval" 
yaml:"resync_interval"`
+       AppNamespaces      []string           `json:"app_namespaces" 
yaml:"app_namespaces"`
+       ElectionID         string             `json:"election_id" 
yaml:"election_id"`
+       IngressClass       string             `json:"ingress_class" 
yaml:"ingress_class"`
+       IngressVersion     string             `json:"ingress_version" 
yaml:"ingress_version"`
+       ApisixRouteVersion string             `json:"apisix_route_version" 
yaml:"apisix_route_version"`
 }
 
 // APISIXConfig contains all APISIX related config items.
@@ -83,12 +88,13 @@ func NewDefaultConfig() *Config {
                HTTPListen:      ":8080",
                EnableProfiling: true,
                Kubernetes: KubernetesConfig{
-                       Kubeconfig:     "", // Use in-cluster configurations.
-                       ResyncInterval: types.TimeDuration{Duration: 6 * 
time.Hour},
-                       AppNamespaces:  []string{v1.NamespaceAll},
-                       ElectionID:     IngressAPISIXLeader,
-                       IngressClass:   IngressClass,
-                       IngressVersion: IngressNetworkingV1,
+                       Kubeconfig:         "", // Use in-cluster 
configurations.
+                       ResyncInterval:     types.TimeDuration{Duration: 6 * 
time.Hour},
+                       AppNamespaces:      []string{v1.NamespaceAll},
+                       ElectionID:         IngressAPISIXLeader,
+                       IngressClass:       IngressClass,
+                       IngressVersion:     IngressNetworkingV1,
+                       ApisixRouteVersion: ApisixRouteV2alpha1,
                },
        }
 }
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 41fd6f4..ae7e868 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -33,12 +33,13 @@ func TestNewConfigFromFile(t *testing.T) {
                HTTPListen:      ":9090",
                EnableProfiling: true,
                Kubernetes: KubernetesConfig{
-                       ResyncInterval: types.TimeDuration{time.Hour},
-                       Kubeconfig:     "/path/to/foo/baz",
-                       AppNamespaces:  []string{""},
-                       ElectionID:     "my-election-id",
-                       IngressClass:   IngressClass,
-                       IngressVersion: IngressNetworkingV1,
+                       ResyncInterval:     types.TimeDuration{time.Hour},
+                       Kubeconfig:         "/path/to/foo/baz",
+                       AppNamespaces:      []string{""},
+                       ElectionID:         "my-election-id",
+                       IngressClass:       IngressClass,
+                       IngressVersion:     IngressNetworkingV1,
+                       ApisixRouteVersion: ApisixRouteV2alpha1,
                },
                APISIX: APISIXConfig{
                        BaseURL:  "http://127.0.0.1:8080/apisix";,
diff --git a/pkg/ingress/controller/apisix_route.go 
b/pkg/ingress/controller/apisix_route.go
index f16ddbb..707cdd9 100644
--- a/pkg/ingress/controller/apisix_route.go
+++ b/pkg/ingress/controller/apisix_route.go
@@ -15,273 +15,263 @@
 package controller
 
 import (
-       "fmt"
-       "time"
+       "context"
 
-       "go.uber.org/zap"
+       "github.com/apache/apisix-ingress-controller/pkg/kube"
+
+       apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 
-       "k8s.io/apimachinery/pkg/api/errors"
-       "k8s.io/apimachinery/pkg/util/runtime"
-       "k8s.io/apimachinery/pkg/util/wait"
-       "k8s.io/client-go/kubernetes"
-       "k8s.io/client-go/kubernetes/scheme"
+       "go.uber.org/zap"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/client-go/tools/cache"
        "k8s.io/client-go/util/workqueue"
 
-       configv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
-       clientset 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned"
-       apisixscheme 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/scheme"
-       apisixinformers 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/config/v1"
-       listersv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v1"
        "github.com/apache/apisix-ingress-controller/pkg/log"
        "github.com/apache/apisix-ingress-controller/pkg/seven/state"
+       "github.com/apache/apisix-ingress-controller/pkg/types"
 )
 
-type ApisixRouteController struct {
-       controller           *Controller
-       kubeclientset        kubernetes.Interface
-       apisixRouteClientset clientset.Interface
-       apisixRouteList      listersv1.ApisixRouteLister
-       apisixRouteSynced    cache.InformerSynced
-       workqueue            workqueue.RateLimitingInterface
-}
-
-type RouteQueueObj struct {
-       Key    string                `json:"key"`
-       OldObj *configv1.ApisixRoute `json:"old_obj"`
-       Ope    string                `json:"ope"` // add / update / delete
+type apisixRouteController struct {
+       controller *Controller
+       workqueue  workqueue.RateLimitingInterface
+       workers    int
 }
 
-func BuildApisixRouteController(
-       kubeclientset kubernetes.Interface,
-       api6RouteClientset clientset.Interface,
-       api6RouteInformer apisixinformers.ApisixRouteInformer,
-       root *Controller) *ApisixRouteController {
-
-       runtime.Must(apisixscheme.AddToScheme(scheme.Scheme))
-       controller := &ApisixRouteController{
-               controller:           root,
-               kubeclientset:        kubeclientset,
-               apisixRouteClientset: api6RouteClientset,
-               apisixRouteList:      api6RouteInformer.Lister(),
-               apisixRouteSynced:    api6RouteInformer.Informer().HasSynced,
-               workqueue:            
workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second,
 60*time.Second, 5), "ApisixRoutes"),
+func (c *Controller) newApisixRouteController() *apisixRouteController {
+       ctl := &apisixRouteController{
+               controller: c,
+               workqueue:  
workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), 
"ApisixRoute"),
+               workers:    1,
        }
-       api6RouteInformer.Informer().AddEventHandler(
+       c.apisixRouteInformer.AddEventHandler(
                cache.ResourceEventHandlerFuncs{
-                       AddFunc:    controller.addFunc,
-                       UpdateFunc: controller.updateFunc,
-                       DeleteFunc: controller.deleteFunc,
-               })
-       return controller
+                       AddFunc:    ctl.onAdd,
+                       UpdateFunc: ctl.onUpdate,
+                       DeleteFunc: ctl.onDelete,
+               },
+       )
+       return ctl
 }
 
-func (c *ApisixRouteController) addFunc(obj interface{}) {
-       var key string
-       var err error
-       if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
-               runtime.HandleError(err)
-               return
-       }
-       if !c.controller.namespaceWatching(key) {
+func (c *apisixRouteController) run(ctx context.Context) {
+       log.Info("ApisixRoute controller started")
+       defer log.Info("ApisixRoute controller exited")
+       ok := cache.WaitForCacheSync(ctx.Done(), 
c.controller.apisixRouteInformer.HasSynced)
+       if !ok {
+               log.Error("cache sync failed")
                return
        }
-       rqo := &RouteQueueObj{Key: key, OldObj: nil, Ope: ADD}
-       c.workqueue.AddRateLimited(rqo)
-}
 
-func (c *ApisixRouteController) updateFunc(oldObj, newObj interface{}) {
-       oldRoute := oldObj.(*configv1.ApisixRoute)
-       newRoute := newObj.(*configv1.ApisixRoute)
-       if oldRoute.ResourceVersion >= newRoute.ResourceVersion {
-               return
+       for i := 0; i < c.workers; i++ {
+               go c.runWorker(ctx)
        }
-       //c.addFunc(newObj)
-       var key string
-       var err error
-       if key, err = cache.MetaNamespaceKeyFunc(newObj); err != nil {
-               runtime.HandleError(err)
-               return
-       }
-       if !c.controller.namespaceWatching(key) {
-               return
-       }
-       rqo := &RouteQueueObj{Key: key, OldObj: oldRoute, Ope: UPDATE}
-       c.workqueue.AddRateLimited(rqo)
+       <-ctx.Done()
+       c.workqueue.ShutDown()
 }
 
-func (c *ApisixRouteController) deleteFunc(obj interface{}) {
-       oldRoute, ok := obj.(*configv1.ApisixRoute)
-       if !ok {
-               oldState, ok := obj.(cache.DeletedFinalStateUnknown)
-               if !ok {
-                       return
-               }
-               oldRoute, ok = oldState.Obj.(*configv1.ApisixRoute)
-               if !ok {
+func (c *apisixRouteController) runWorker(ctx context.Context) {
+       for {
+               obj, quit := c.workqueue.Get()
+               if quit {
                        return
                }
+               err := c.sync(ctx, obj.(*types.Event))
+               c.workqueue.Done(obj)
+               c.handleSyncErr(obj, err)
        }
-       var key string
-       var err error
-       key, err = cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
+}
+
+func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) 
error {
+       obj := ev.Object.(kube.ApisixRouteEvent)
+       namespace, name, err := cache.SplitMetaNamespaceKey(obj.Key)
        if err != nil {
-               runtime.HandleError(err)
-               return
+               log.Errorf("invalid resource key: %s", obj.Key)
+               return err
        }
-       if !c.controller.namespaceWatching(key) {
-               return
+       var (
+               ar        kube.ApisixRoute
+               routes    []*apisixv1.Route
+               upstreams []*apisixv1.Upstream
+       )
+       if obj.GroupVersion == kube.ApisixRouteV1 {
+               ar, err = c.controller.apisixRouteLister.V1(namespace, name)
+       } else {
+               ar, err = c.controller.apisixRouteLister.V2alpha1(namespace, 
name)
        }
-       rqo := &RouteQueueObj{Key: key, OldObj: oldRoute, Ope: DELETE}
-       c.workqueue.AddRateLimited(rqo)
-}
 
-func (c *ApisixRouteController) Run(stop <-chan struct{}) error {
-       if ok := cache.WaitForCacheSync(stop); !ok {
-               log.Errorf("同步缓存失败")
-               return fmt.Errorf("failed to wait for caches to sync")
-       }
-       go wait.Until(c.runWorker, time.Second, stop)
-       return nil
-}
+       if err != nil {
+               if !k8serrors.IsNotFound(err) {
+                       log.Errorw("failed to get ApisixRoute",
+                               zap.String("version", obj.GroupVersion),
+                               zap.String("key", obj.Key),
+                               zap.Error(err),
+                       )
+                       return err
+               }
 
-func (c *ApisixRouteController) runWorker() {
-       for c.processNextWorkItem() {
+               if ev.Type != types.EventDelete {
+                       log.Warnw("ApisixRoute was deleted before it can be 
delivered",
+                               zap.String("key", obj.Key),
+                               zap.String("version", obj.GroupVersion),
+                       )
+                       return nil
+               }
        }
-}
-
-func (c *ApisixRouteController) processNextWorkItem() bool {
-       defer recoverException()
-       obj, shutdown := c.workqueue.Get()
-       if shutdown {
-               return false
+       if ev.Type == types.EventDelete {
+               if ar != nil {
+                       // We still find the resource while we are processing 
the DELETE event,
+                       // that means object with same namespace and name was 
created, discarding
+                       // this stale DELETE event.
+                       log.Warnw("discard the stale ApisixRoute delete event 
since the resource still exists",
+                               zap.String("key", obj.Key),
+                       )
+                       return nil
+               }
+               ar = ev.Tombstone.(kube.ApisixRoute)
        }
-       err := func(obj interface{}) error {
-               defer c.workqueue.Done(obj)
-               var ok bool
-               var rqo *RouteQueueObj
-               if rqo, ok = obj.(*RouteQueueObj); !ok {
-                       c.workqueue.Forget(obj)
-                       return fmt.Errorf("expected RouteQueueObj in workqueue 
but got %#v", obj)
+       if obj.GroupVersion == kube.ApisixRouteV1 {
+               routes, upstreams, err = 
c.controller.translator.TranslateRouteV1(ar.V1())
+               if err != nil {
+                       log.Errorw("failed to translate ApisixRoute v1",
+                               zap.Error(err),
+                               zap.Any("object", ar),
+                       )
+                       return err
                }
-               if err := c.syncHandler(rqo); err != nil {
-                       c.workqueue.AddRateLimited(obj)
-                       log.Errorf("sync route %s failed", rqo.Key)
-                       return fmt.Errorf("error syncing '%s': %s", rqo.Key, 
err.Error())
+       } else {
+               routes, upstreams, err = 
c.controller.translator.TranslateRouteV2alpha1(ar.V2alpha1())
+               if err != nil {
+                       log.Errorw("failed to translate ApisixRoute v2alpha1",
+                               zap.Error(err),
+                               zap.Any("object", ar),
+                       )
+                       return err
                }
-
-               c.workqueue.Forget(obj)
-               return nil
-       }(obj)
-       if err != nil {
-               runtime.HandleError(err)
        }
-       return true
-}
 
-func (c *ApisixRouteController) syncHandler(rqo *RouteQueueObj) error {
-       key := rqo.Key
-       switch {
-       case rqo.Ope == ADD:
-               return c.add(key)
-       case rqo.Ope == UPDATE:
-               // 1.first add new route config
-               if err := c.add(key); err != nil {
-                       // log error
+       log.Debugw("translated ApisixRoute",
+               zap.Any("routes", routes),
+               zap.Any("upstreams", upstreams),
+               zap.Any("apisix_route", ar),
+       )
+
+       if ev.Type == types.EventDelete {
+               rc := &state.RouteCompare{OldRoutes: routes, NewRoutes: nil}
+               if err := rc.Sync(); err != nil {
+                       return err
+               } else {
+                       comb := state.ApisixCombination{Routes: nil, Upstreams: 
upstreams}
+                       if err := comb.Remove(); err != nil {
+                               return err
+                       }
+               }
+               return nil
+       } else if ev.Type == types.EventAdd {
+               comb := state.ApisixCombination{Routes: routes, Upstreams: 
upstreams}
+               if _, err := comb.Solver(); err != nil {
                        return err
+               }
+       } else {
+               var oldRoutes []*apisixv1.Route
+               if obj.GroupVersion == kube.ApisixRouteV1 {
+                       oldRoutes, _, _ = 
c.controller.translator.TranslateRouteV1(ar.V1())
                } else {
-                       // 2.then delete routes not exist
-                       return c.sync(rqo)
+                       oldRoutes, _, _ = 
c.controller.translator.TranslateRouteV2alpha1(ar.V2alpha1())
                }
-       case rqo.Ope == DELETE:
-               return c.sync(rqo)
-       default:
-               // log error
-               return fmt.Errorf("RouteQueueObj is not expected")
+               rc := &state.RouteCompare{OldRoutes: oldRoutes, NewRoutes: 
routes}
+               return rc.Sync()
        }
+       return nil
 }
 
-func (c *ApisixRouteController) add(key string) error {
-       namespace, name, err := cache.SplitMetaNamespaceKey(key)
-       if err != nil {
-               log.Errorf("invalid resource key: %s", key)
-               return fmt.Errorf("invalid resource key: %s", key)
-       }
-
-       apisixIngressRoute, err := 
c.apisixRouteList.ApisixRoutes(namespace).Get(name)
-       if err != nil {
-               if errors.IsNotFound(err) {
-                       log.Infof("apisixRoute %s is removed", key)
-                       return nil
-               }
-               log.Errorf("failed to list ApisixRoute %s: %s", key, 
err.Error())
-               runtime.HandleError(fmt.Errorf("failed to list ApisixRoute %s: 
%s", key, err.Error()))
-               return err
+func (c *apisixRouteController) handleSyncErr(obj interface{}, err error) {
+       if err == nil {
+               c.workqueue.Forget(obj)
+               return
        }
-       routes, upstreams, err := 
c.controller.translator.TranslateRouteV1(apisixIngressRoute)
-       if err != nil {
-               log.Errorw("failed to translate ApisixRoute/v1",
-                       zap.Any("route", apisixIngressRoute),
-                       zap.Error(err),
+       if c.workqueue.NumRequeues(obj) < _maxRetries {
+               log.Infow("sync ApisixRoute failed, will retry",
+                       zap.Any("object", obj),
                )
-               return err
+               c.workqueue.AddRateLimited(obj)
+       } else {
+               c.workqueue.Forget(obj)
+               log.Warnf("drop ApisixRoute %+v out of the queue", obj)
        }
-       comb := state.ApisixCombination{Routes: routes, Upstreams: upstreams}
-       _, err = comb.Solver()
+}
+
+func (c *apisixRouteController) onAdd(obj interface{}) {
+       key, err := cache.MetaNamespaceKeyFunc(obj)
        if err != nil {
-               log.Errorw("failed to push routes and upstreams to APISIX",
-                       zap.Any("routes", routes),
-                       zap.Any("upstreams", upstreams),
-                       zap.Error(err),
-               )
+               log.Errorf("found ApisixRoute resource with bad meta namespace 
key: %s", err)
+               return
+       }
+       if !c.controller.namespaceWatching(key) {
+               return
        }
-       return err
+       log.Debugw("ApisixRoute add event arrived",
+               zap.Any("object", obj))
 
+       ar := kube.MustNewApisixRoute(obj)
+       c.workqueue.AddRateLimited(&types.Event{
+               Type: types.EventAdd,
+               Object: kube.ApisixRouteEvent{
+                       Key:          key,
+                       GroupVersion: ar.GroupVersion(),
+               },
+       })
 }
 
-// sync
-// 1.diff routes between old and new objects
-// 2.delete routes not exist
-func (c *ApisixRouteController) sync(rqo *RouteQueueObj) error {
-       key := rqo.Key
-       namespace, name, err := cache.SplitMetaNamespaceKey(key)
+func (c *apisixRouteController) onUpdate(oldObj, newObj interface{}) {
+       prev := kube.MustNewApisixRoute(oldObj)
+       curr := kube.MustNewApisixRoute(newObj)
+       if prev.ResourceVersion() >= curr.ResourceVersion() {
+               return
+       }
+       key, err := cache.MetaNamespaceKeyFunc(newObj)
        if err != nil {
-               log.Errorf("invalid resource key: %s", key)
-               return fmt.Errorf("invalid resource key: %s", key)
+               log.Errorf("found ApisixRoute resource with bad meta namespace 
key: %s", err)
+               return
        }
-       switch {
-       case rqo.Ope == UPDATE:
-               apisixIngressRoute, err := 
c.apisixRouteList.ApisixRoutes(namespace).Get(name)
-               if err != nil {
-                       if errors.IsNotFound(err) {
-                               log.Errorf("apisixRoute %s is removed", key)
-                               return nil
-                       }
-                       return err // if error occurred, return
-               }
-               oldRoutes, _, _ := 
c.controller.translator.TranslateRouteV1(rqo.OldObj)
-               newRoutes, _, _ := 
c.controller.translator.TranslateRouteV1(apisixIngressRoute)
+       if !c.controller.namespaceWatching(key) {
+               return
+       }
+       c.workqueue.AddRateLimited(&types.Event{
+               Type: types.EventUpdate,
+               Object: kube.ApisixRouteEvent{
+                       Key:          key,
+                       GroupVersion: curr.GroupVersion(),
+                       OldObject:    prev,
+               },
+       })
+}
 
-               rc := &state.RouteCompare{OldRoutes: oldRoutes, NewRoutes: 
newRoutes}
-               return rc.Sync()
-       case rqo.Ope == DELETE:
-               apisixIngressRoute, _ := 
c.apisixRouteList.ApisixRoutes(namespace).Get(name)
-               if apisixIngressRoute != nil && 
apisixIngressRoute.ResourceVersion > rqo.OldObj.ResourceVersion {
-                       log.Warnf("Route %s has been covered when retry", 
rqo.Key)
-                       return nil
-               }
-               routes, upstreams, _ := 
c.controller.translator.TranslateRouteV1(rqo.OldObj)
-               rc := &state.RouteCompare{OldRoutes: routes, NewRoutes: nil}
-               if err := rc.Sync(); err != nil {
-                       return err
-               } else {
-                       comb := state.ApisixCombination{Routes: nil, Upstreams: 
upstreams}
-                       if err := comb.Remove(); err != nil {
-                               return err
-                       }
+func (c *apisixRouteController) onDelete(obj interface{}) {
+       ar, err := kube.NewApisixRoute(obj)
+       if err != nil {
+               tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
+               if !ok {
+                       return
                }
-               return nil
-       default:
-               return fmt.Errorf("not expected in (ApisixRouteController) 
sync")
+               ar = kube.MustNewApisixRoute(tombstone)
+       }
+       key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
+       if err != nil {
+               log.Errorf("found ApisixRoute resource with bad meta namesapce 
key: %s", err)
+               return
+       }
+       if !c.controller.namespaceWatching(key) {
+               return
        }
+       log.Debugw("ApisixRoute delete event arrived",
+               zap.Any("final state", ar),
+       )
+       c.workqueue.AddRateLimited(&types.Event{
+               Type: types.EventDelete,
+               Object: kube.ApisixRouteEvent{
+                       Key:          key,
+                       GroupVersion: ar.GroupVersion(),
+               },
+               Tombstone: ar,
+       })
 }
diff --git a/pkg/ingress/controller/apisix_upstream.go 
b/pkg/ingress/controller/apisix_upstream.go
index ba116ad..c03ed9c 100644
--- a/pkg/ingress/controller/apisix_upstream.go
+++ b/pkg/ingress/controller/apisix_upstream.go
@@ -46,7 +46,7 @@ func (c *Controller) newApisixUpstreamController() 
*apisixUpstreamController {
                cache.ResourceEventHandlerFuncs{
                        AddFunc:    ctl.onAdd,
                        UpdateFunc: ctl.onUpdate,
-                       DeleteFunc: ctl.OnDelete,
+                       DeleteFunc: ctl.onDelete,
                },
        )
        return ctl
@@ -56,7 +56,7 @@ func (c *apisixUpstreamController) run(ctx context.Context) {
        log.Info("ApisixUpstream controller started")
        defer log.Info("ApisixUpstream controller exited")
        if ok := cache.WaitForCacheSync(ctx.Done(), 
c.controller.apisixUpstreamInformer.HasSynced, 
c.controller.svcInformer.HasSynced); !ok {
-               log.Errorf("cache sync failed")
+               log.Error("cache sync failed")
                return
        }
        for i := 0; i < c.workers; i++ {
@@ -179,13 +179,13 @@ func (c *apisixUpstreamController) handleSyncErr(obj 
interface{}, err error) {
                return
        }
        if c.workqueue.NumRequeues(obj) < _maxRetries {
-               log.Infow("sync endpoints failed, will retry",
+               log.Infow("sync ApisixUpstream failed, will retry",
                        zap.Any("object", obj),
                )
                c.workqueue.AddRateLimited(obj)
        } else {
                c.workqueue.Forget(obj)
-               log.Warnf("drop endpoints %+v out of the queue", obj)
+               log.Warnf("drop ApisixUpstream %+v out of the queue", obj)
        }
 }
 
@@ -232,7 +232,7 @@ func (c *apisixUpstreamController) onUpdate(oldObj, newObj 
interface{}) {
        })
 }
 
-func (c *apisixUpstreamController) OnDelete(obj interface{}) {
+func (c *apisixUpstreamController) onDelete(obj interface{}) {
        au, ok := obj.(*configv1.ApisixUpstream)
        if !ok {
                tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
diff --git a/pkg/ingress/controller/controller.go 
b/pkg/ingress/controller/controller.go
index 2fb66ef..f12c528 100644
--- a/pkg/ingress/controller/controller.go
+++ b/pkg/ingress/controller/controller.go
@@ -77,11 +77,14 @@ type Controller struct {
        ingressInformer        cache.SharedIndexInformer
        apisixUpstreamInformer cache.SharedIndexInformer
        apisixUpstreamLister   listersv1.ApisixUpstreamLister
+       apisixRouteLister      kube.ApisixRouteLister
+       apisixRouteInformer    cache.SharedIndexInformer
 
        // resource controllers
        endpointsController      *endpointsController
        ingressController        *ingressController
        apisixUpstreamController *apisixUpstreamController
+       apisixRouteController    *apisixRouteController
 }
 
 // NewController creates an ingress apisix controller object.
@@ -110,8 +113,9 @@ func NewController(cfg *config.Config) (*Controller, error) 
{
        sharedInformerFactory := 
externalversions.NewSharedInformerFactory(crdClientset, 
cfg.Kubernetes.ResyncInterval.Duration)
 
        var (
-               watchingNamespace map[string]struct{}
-               ingressInformer   cache.SharedIndexInformer
+               watchingNamespace   map[string]struct{}
+               ingressInformer     cache.SharedIndexInformer
+               apisixRouteInformer cache.SharedIndexInformer
        )
        if len(cfg.Kubernetes.AppNamespaces) > 1 || 
cfg.Kubernetes.AppNamespaces[0] != v1.NamespaceAll {
                watchingNamespace = make(map[string]struct{}, 
len(cfg.Kubernetes.AppNamespaces))
@@ -123,12 +127,19 @@ func NewController(cfg *config.Config) (*Controller, 
error) {
 
        ingressLister := 
kube.NewIngressLister(kube.CoreSharedInformerFactory.Networking().V1().Ingresses().Lister(),
                
kube.CoreSharedInformerFactory.Networking().V1beta1().Ingresses().Lister())
+       apisixRouteLister := 
kube.NewApisixRouteLister(sharedInformerFactory.Apisix().V1().ApisixRoutes().Lister(),
+               
sharedInformerFactory.Apisix().V2alpha1().ApisixRoutes().Lister())
 
        if cfg.Kubernetes.IngressVersion == config.IngressNetworkingV1 {
                ingressInformer = 
kube.CoreSharedInformerFactory.Networking().V1().Ingresses().Informer()
        } else {
                ingressInformer = 
kube.CoreSharedInformerFactory.Extensions().V1beta1().Ingresses().Informer()
        }
+       if cfg.Kubernetes.ApisixRouteVersion == config.ApisixRouteV2alpha1 {
+               apisixRouteInformer = 
sharedInformerFactory.Apisix().V2alpha1().ApisixRoutes().Informer()
+       } else {
+               apisixRouteInformer = 
sharedInformerFactory.Apisix().V1().ApisixRoutes().Informer()
+       }
 
        c := &Controller{
                name:               podName,
@@ -148,6 +159,8 @@ func NewController(cfg *config.Config) (*Controller, error) 
{
                svcLister:              
kube.CoreSharedInformerFactory.Core().V1().Services().Lister(),
                ingressLister:          ingressLister,
                ingressInformer:        ingressInformer,
+               apisixRouteInformer:    apisixRouteInformer,
+               apisixRouteLister:      apisixRouteLister,
                apisixUpstreamInformer: 
sharedInformerFactory.Apisix().V1().ApisixUpstreams().Informer(),
                apisixUpstreamLister:   
sharedInformerFactory.Apisix().V1().ApisixUpstreams().Lister(),
        }
@@ -159,6 +172,7 @@ func NewController(cfg *config.Config) (*Controller, error) 
{
 
        c.endpointsController = c.newEndpointsController()
        c.apisixUpstreamController = c.newApisixUpstreamController()
+       c.apisixRouteController = c.newApisixRouteController()
        c.ingressController = c.newIngressController()
 
        return c, nil
@@ -290,6 +304,9 @@ func (c *Controller) run(ctx context.Context) {
        c.goAttach(func() {
                c.ingressController.run(ctx)
        })
+       c.goAttach(func() {
+               c.apisixRouteController.run(ctx)
+       })
 
        ac := &Api6Controller{
                KubeClientSet:             c.clientset,
@@ -299,8 +316,6 @@ func (c *Controller) run(ctx context.Context) {
                Stop:                      ctx.Done(),
        }
 
-       // ApisixRoute
-       ac.ApisixRoute(c)
        // ApisixTLS
        ac.ApisixTLS(c)
 
@@ -338,17 +353,6 @@ type Api6Controller struct {
        Stop                      <-chan struct{}
 }
 
-func (api6 *Api6Controller) ApisixRoute(controller *Controller) {
-       arc := BuildApisixRouteController(
-               api6.KubeClientSet,
-               api6.Api6ClientSet,
-               api6.SharedInformerFactory.Apisix().V1().ApisixRoutes(),
-               controller)
-       if err := arc.Run(api6.Stop); err != nil {
-               log.Errorf("failed to run ApisixRouteController: %s", err)
-       }
-}
-
 func (api6 *Api6Controller) ApisixTLS(controller *Controller) {
        atc := BuildApisixTlsController(
                api6.KubeClientSet,
diff --git a/pkg/ingress/controller/ingress.go 
b/pkg/ingress/controller/ingress.go
index fe0f108..5a042b5 100644
--- a/pkg/ingress/controller/ingress.go
+++ b/pkg/ingress/controller/ingress.go
@@ -87,6 +87,7 @@ func (c *ingressController) sync(ctx context.Context, ev 
*types.Event) error {
        namespace, name, err := cache.SplitMetaNamespaceKey(ingEv.Key)
        if err != nil {
                log.Errorf("found ingress resource with invalid meta namespace 
key %s: %s", ingEv.Key, err)
+               return err
        }
 
        var ing kube.Ingress
diff --git a/pkg/kube/apisix/apis/config/v2alpha1/doc.go 
b/pkg/kube/apisix/apis/config/v2alpha1/doc.go
new file mode 100644
index 0000000..fd42d17
--- /dev/null
+++ b/pkg/kube/apisix/apis/config/v2alpha1/doc.go
@@ -0,0 +1,18 @@
+// 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.
+// +k8s:deepcopy-gen=package
+
+// +groupName=apisix.apache.org
+package v2alpha1
diff --git a/pkg/kube/apisix/apis/config/v2alpha1/register.go 
b/pkg/kube/apisix/apis/config/v2alpha1/register.go
new file mode 100644
index 0000000..5af6a1b
--- /dev/null
+++ b/pkg/kube/apisix/apis/config/v2alpha1/register.go
@@ -0,0 +1,50 @@
+// 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 v2alpha1
+
+import (
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+const (
+       _groupName = "apisix.apache.org"
+       _version   = "v2alpha1"
+)
+
+var (
+       SchemeGroupVersion = schema.GroupVersion{
+               Group:   _groupName,
+               Version: _version,
+       }
+       SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+       AddToScheme   = SchemeBuilder.AddToScheme
+)
+
+func Resource(resource string) schema.GroupResource {
+       return SchemeGroupVersion.WithResource(resource).GroupResource()
+}
+
+func addKnownTypes(scheme *runtime.Scheme) error {
+       scheme.AddKnownTypes(SchemeGroupVersion,
+               &ApisixRoute{},
+               &ApisixRouteList{},
+       )
+
+       // register the type in the scheme
+       metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
+       return nil
+}
diff --git a/pkg/kube/apisix/apis/config/v2alpha1/types.go 
b/pkg/kube/apisix/apis/config/v2alpha1/types.go
new file mode 100644
index 0000000..4e5ab94
--- /dev/null
+++ b/pkg/kube/apisix/apis/config/v2alpha1/types.go
@@ -0,0 +1,163 @@
+// 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 v2alpha1
+
+import (
+       "encoding/json"
+
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/util/intstr"
+)
+
+// +genclient
+// +genclient:noStatus
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+// 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"`
+}
+
+// ApisixRouteSpec is the spec definition for ApisixRouteSpec.
+type ApisixRouteSpec struct {
+       HTTP []*ApisixRouteHTTP `json:"http,omitempty"`
+}
+
+// ApisixRouteHTTP represents a single route in for HTTP traffic.
+type ApisixRouteHTTP struct {
+       // The rule name, cannot be empty.
+       Name string `json:"name"`
+       // Route priority, when multiple routes contains
+       // same URI path (for path matching), route with
+       // higher priority will take effect.
+       Priority int                      `json:"priority,omitempty"`
+       Match    *ApisixRouteHTTPMatch    `json:"match,omitempty"`
+       Backend  *ApisixRouteHTTPBackend  `json:"backend"`
+       Plugins  []*ApisixRouteHTTPPlugin `json:"plugins,omitempty"`
+}
+
+// ApisixRouteHTTPMatch represents the match condition for hitting this route.
+type ApisixRouteHTTPMatch struct {
+       // URI path predicates, at least one path should be
+       // configured, path could be exact or prefix, for prefix path,
+       // append "*" after it, for instance, "/foo*".
+       Paths []string `json:"paths"`
+       // HTTP request method predicates.
+       Methods []string `json:"methods,omitempty"`
+       // HTTP Host predicates, host can be a wildcard domain or
+       // an exact domain. For wildcard domain, only one generic
+       // level is allowed, for instance, "*.foo.com" is valid but
+       // "*.*.foo.com" is not.
+       Hosts []string `json:"hosts,omitempty"`
+       // Remote address predicates, items can be valid IPv4 address
+       // or IPv6 address or CIDR.
+       RemoteAddrs []string `json:"remoteAddrs,omitempty"`
+       // NginxVars represents generic match predicates,
+       // it uses Nginx variable systems, so any predicate
+       // like headers, querystring and etc can be leveraged
+       // here to match the route.
+       // For instance, it can be:
+       // nginxVars:
+       //   - subject: "$remote_addr"
+       //     op: in
+       //     value:
+       //       - "127.0.0.1"
+       //       - "10.0.5.11"
+       NginxVars []ApisixRouteHTTPMatchNginxVar `json:"nginxVars,omitempty"`
+}
+
+// ApisixRouteHTTPMatchNginxVar represents a binary expression for the Nginx 
vars.
+type ApisixRouteHTTPMatchNginxVar struct {
+       // Subject is the expression subject, it can
+       // be any string composed by literals and nginx
+       // vars.
+       Subject string `json:"subject"`
+       // Op is the operator, can be:
+       // - "==": equal
+       // - "~=": not equal
+       // - ">": greater than
+       // - ">=": greater than or equal to
+       // - "<": less then
+       // - "<=": less then or equal to
+       // - "~~": regex match
+       // - "!~~": regex not match
+       // - "~*": case insensitive regex match
+       // - "!~*": case insensitive regex not match
+       // - "in": set match, Value should be a string array.
+       // - "not_in": set match, Value should be a string array.
+       // - "contain": subject contains the Value (inclusion relation).
+       // - "not_contain": subject doesn't contain the Value (inclusion 
relation).
+       Op string `json:"op"`
+       // Array is an array type object of the expression.
+       // It should be used when the Op is "in" or "not_in";
+       Array []string `json:"array"`
+       // Value is the normal type object for the expression,
+       // it should be used when the Op is not "in" and "not_in".
+       // Array and Value are exclusive so only of them can be set
+       // in the same time.
+       Value *string `json:"value"`
+}
+
+// ApisixRouteHTTPBackend represents a HTTP backend (a Kuberentes Service).
+type ApisixRouteHTTPBackend struct {
+       // The name (short) of the service, note cross namespace is forbidden,
+       // so be sure the ApisixRoute and Service are in the same namespace.
+       ServiceName string `json:"serviceName"`
+       // The service port, could be the name or the port number.
+       ServicePort intstr.IntOrString `json:"servicePort"`
+       // The resolve granularity, can be "endpoints" or "service",
+       // when set to "endpoints", the pod ips will be used; other
+       // wise, the service ClusterIP or ExternalIP will be used,
+       // default is endpoints.
+       ResolveGranularity string `json:"resolveGranularity"`
+}
+
+// ApisixRouteHTTPPlugin represents an APISIX plugin.
+type ApisixRouteHTTPPlugin struct {
+       // The plugin name.
+       Name string `json:"name"`
+       // Whether this plugin is in use, default is true.
+       Enable bool `json:"enable"`
+       // Plugin configuration.
+       // TODO we may use protobuf to define it.
+       Config ApisixRouteHTTPPluginConfig
+}
+
+// ApisixRouteHTTPPluginConfig is the configuration for
+// any plugins.
+type ApisixRouteHTTPPluginConfig map[string]interface{}
+
+func (p ApisixRouteHTTPPluginConfig) DeepCopyInto(out 
*ApisixRouteHTTPPluginConfig) {
+       b, _ := json.Marshal(&p)
+       _ = json.Unmarshal(b, out)
+}
+
+func (p *ApisixRouteHTTPPluginConfig) DeepCopy() *ApisixRouteHTTPPluginConfig {
+       if p == nil {
+               return nil
+       }
+       out := new(ApisixRouteHTTPPluginConfig)
+       p.DeepCopyInto(out)
+       return out
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+type ApisixRouteList struct {
+       metav1.TypeMeta `json:",inline"`
+       metav1.ListMeta `json:"metadata"`
+       Items           []ApisixRoute `json:"items,omitempty"`
+}
diff --git a/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go 
b/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go
new file mode 100644
index 0000000..5fd71bf
--- /dev/null
+++ b/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,256 @@
+// +build !ignore_autogenerated
+
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by deepcopy-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+       runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRoute) DeepCopyInto(out *ApisixRoute) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+       if in.Spec != nil {
+               in, out := &in.Spec, &out.Spec
+               *out = new(ApisixRouteSpec)
+               (*in).DeepCopyInto(*out)
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRoute.
+func (in *ApisixRoute) DeepCopy() *ApisixRoute {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRoute)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *ApisixRoute) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteHTTP) DeepCopyInto(out *ApisixRouteHTTP) {
+       *out = *in
+       if in.Match != nil {
+               in, out := &in.Match, &out.Match
+               *out = new(ApisixRouteHTTPMatch)
+               (*in).DeepCopyInto(*out)
+       }
+       if in.Backend != nil {
+               in, out := &in.Backend, &out.Backend
+               *out = new(ApisixRouteHTTPBackend)
+               **out = **in
+       }
+       if in.Plugins != nil {
+               in, out := &in.Plugins, &out.Plugins
+               *out = make([]*ApisixRouteHTTPPlugin, len(*in))
+               for i := range *in {
+                       if (*in)[i] != nil {
+                               in, out := &(*in)[i], &(*out)[i]
+                               *out = new(ApisixRouteHTTPPlugin)
+                               (*in).DeepCopyInto(*out)
+                       }
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteHTTP.
+func (in *ApisixRouteHTTP) DeepCopy() *ApisixRouteHTTP {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteHTTP)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteHTTPBackend) DeepCopyInto(out *ApisixRouteHTTPBackend) {
+       *out = *in
+       out.ServicePort = in.ServicePort
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteHTTPBackend.
+func (in *ApisixRouteHTTPBackend) DeepCopy() *ApisixRouteHTTPBackend {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteHTTPBackend)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteHTTPMatch) DeepCopyInto(out *ApisixRouteHTTPMatch) {
+       *out = *in
+       if in.Paths != nil {
+               in, out := &in.Paths, &out.Paths
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       if in.Methods != nil {
+               in, out := &in.Methods, &out.Methods
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       if in.Hosts != nil {
+               in, out := &in.Hosts, &out.Hosts
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       if in.RemoteAddrs != nil {
+               in, out := &in.RemoteAddrs, &out.RemoteAddrs
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       if in.NginxVars != nil {
+               in, out := &in.NginxVars, &out.NginxVars
+               *out = make([]ApisixRouteHTTPMatchNginxVar, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteHTTPMatch.
+func (in *ApisixRouteHTTPMatch) DeepCopy() *ApisixRouteHTTPMatch {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteHTTPMatch)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteHTTPMatchNginxVar) DeepCopyInto(out 
*ApisixRouteHTTPMatchNginxVar) {
+       *out = *in
+       if in.Array != nil {
+               in, out := &in.Array, &out.Array
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       if in.Value != nil {
+               in, out := &in.Value, &out.Value
+               *out = new(string)
+               **out = **in
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteHTTPMatchNginxVar.
+func (in *ApisixRouteHTTPMatchNginxVar) DeepCopy() 
*ApisixRouteHTTPMatchNginxVar {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteHTTPMatchNginxVar)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteHTTPPlugin) DeepCopyInto(out *ApisixRouteHTTPPlugin) {
+       *out = *in
+       in.Config.DeepCopyInto(&out.Config)
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteHTTPPlugin.
+func (in *ApisixRouteHTTPPlugin) DeepCopy() *ApisixRouteHTTPPlugin {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteHTTPPlugin)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteList) DeepCopyInto(out *ApisixRouteList) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ListMeta.DeepCopyInto(&out.ListMeta)
+       if in.Items != nil {
+               in, out := &in.Items, &out.Items
+               *out = make([]ApisixRoute, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteList.
+func (in *ApisixRouteList) DeepCopy() *ApisixRouteList {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteList)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *ApisixRouteList) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *ApisixRouteSpec) DeepCopyInto(out *ApisixRouteSpec) {
+       *out = *in
+       if in.HTTP != nil {
+               in, out := &in.HTTP, &out.HTTP
+               *out = make([]*ApisixRouteHTTP, len(*in))
+               for i := range *in {
+                       if (*in)[i] != nil {
+                               in, out := &(*in)[i], &(*out)[i]
+                               *out = new(ApisixRouteHTTP)
+                               (*in).DeepCopyInto(*out)
+                       }
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ApisixRouteSpec.
+func (in *ApisixRouteSpec) DeepCopy() *ApisixRouteSpec {
+       if in == nil {
+               return nil
+       }
+       out := new(ApisixRouteSpec)
+       in.DeepCopyInto(out)
+       return out
+}
diff --git a/pkg/kube/apisix/client/clientset/versioned/clientset.go 
b/pkg/kube/apisix/client/clientset/versioned/clientset.go
index f85e3fd..1e82ba4 100644
--- a/pkg/kube/apisix/client/clientset/versioned/clientset.go
+++ b/pkg/kube/apisix/client/clientset/versioned/clientset.go
@@ -22,6 +22,7 @@ import (
        "fmt"
 
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v1"
+       apisixv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1"
        discovery "k8s.io/client-go/discovery"
        rest "k8s.io/client-go/rest"
        flowcontrol "k8s.io/client-go/util/flowcontrol"
@@ -30,13 +31,15 @@ import (
 type Interface interface {
        Discovery() discovery.DiscoveryInterface
        ApisixV1() apisixv1.ApisixV1Interface
+       ApisixV2alpha1() apisixv2alpha1.ApisixV2alpha1Interface
 }
 
 // Clientset contains the clients for groups. Each group has exactly one
 // version included in a Clientset.
 type Clientset struct {
        *discovery.DiscoveryClient
-       apisixV1 *apisixv1.ApisixV1Client
+       apisixV1       *apisixv1.ApisixV1Client
+       apisixV2alpha1 *apisixv2alpha1.ApisixV2alpha1Client
 }
 
 // ApisixV1 retrieves the ApisixV1Client
@@ -44,6 +47,11 @@ func (c *Clientset) ApisixV1() apisixv1.ApisixV1Interface {
        return c.apisixV1
 }
 
+// ApisixV2alpha1 retrieves the ApisixV2alpha1Client
+func (c *Clientset) ApisixV2alpha1() apisixv2alpha1.ApisixV2alpha1Interface {
+       return c.apisixV2alpha1
+}
+
 // Discovery retrieves the DiscoveryClient
 func (c *Clientset) Discovery() discovery.DiscoveryInterface {
        if c == nil {
@@ -69,6 +77,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
        if err != nil {
                return nil, err
        }
+       cs.apisixV2alpha1, err = apisixv2alpha1.NewForConfig(&configShallowCopy)
+       if err != nil {
+               return nil, err
+       }
 
        cs.DiscoveryClient, err = 
discovery.NewDiscoveryClientForConfig(&configShallowCopy)
        if err != nil {
@@ -82,6 +94,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
 func NewForConfigOrDie(c *rest.Config) *Clientset {
        var cs Clientset
        cs.apisixV1 = apisixv1.NewForConfigOrDie(c)
+       cs.apisixV2alpha1 = apisixv2alpha1.NewForConfigOrDie(c)
 
        cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
        return &cs
@@ -91,6 +104,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
 func New(c rest.Interface) *Clientset {
        var cs Clientset
        cs.apisixV1 = apisixv1.New(c)
+       cs.apisixV2alpha1 = apisixv2alpha1.New(c)
 
        cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
        return &cs
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/fake/clientset_generated.go 
b/pkg/kube/apisix/client/clientset/versioned/fake/clientset_generated.go
index 7e27814..61caf81 100644
--- a/pkg/kube/apisix/client/clientset/versioned/fake/clientset_generated.go
+++ b/pkg/kube/apisix/client/clientset/versioned/fake/clientset_generated.go
@@ -22,6 +22,8 @@ import (
        clientset 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned"
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v1"
        fakeapisixv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v1/fake"
+       apisixv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1"
+       fakeapisixv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake"
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/apimachinery/pkg/watch"
        "k8s.io/client-go/discovery"
@@ -80,3 +82,8 @@ var _ clientset.Interface = &Clientset{}
 func (c *Clientset) ApisixV1() apisixv1.ApisixV1Interface {
        return &fakeapisixv1.FakeApisixV1{Fake: &c.Fake}
 }
+
+// ApisixV2alpha1 retrieves the ApisixV2alpha1Client
+func (c *Clientset) ApisixV2alpha1() apisixv2alpha1.ApisixV2alpha1Interface {
+       return &fakeapisixv2alpha1.FakeApisixV2alpha1{Fake: &c.Fake}
+}
diff --git a/pkg/kube/apisix/client/clientset/versioned/fake/register.go 
b/pkg/kube/apisix/client/clientset/versioned/fake/register.go
index 153181f..c013698 100644
--- a/pkg/kube/apisix/client/clientset/versioned/fake/register.go
+++ b/pkg/kube/apisix/client/clientset/versioned/fake/register.go
@@ -20,6 +20,7 @@ package fake
 
 import (
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
+       apisixv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        runtime "k8s.io/apimachinery/pkg/runtime"
        schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -32,6 +33,7 @@ var codecs = serializer.NewCodecFactory(scheme)
 
 var localSchemeBuilder = runtime.SchemeBuilder{
        apisixv1.AddToScheme,
+       apisixv2alpha1.AddToScheme,
 }
 
 // AddToScheme adds all types of this clientset into the given scheme. This 
allows composition
diff --git a/pkg/kube/apisix/client/clientset/versioned/scheme/register.go 
b/pkg/kube/apisix/client/clientset/versioned/scheme/register.go
index f91acfa..00b3917 100644
--- a/pkg/kube/apisix/client/clientset/versioned/scheme/register.go
+++ b/pkg/kube/apisix/client/clientset/versioned/scheme/register.go
@@ -20,6 +20,7 @@ package scheme
 
 import (
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
+       apisixv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        runtime "k8s.io/apimachinery/pkg/runtime"
        schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -32,6 +33,7 @@ var Codecs = serializer.NewCodecFactory(Scheme)
 var ParameterCodec = runtime.NewParameterCodec(Scheme)
 var localSchemeBuilder = runtime.SchemeBuilder{
        apisixv1.AddToScheme,
+       apisixv2alpha1.AddToScheme,
 }
 
 // AddToScheme adds all types of this clientset into the given scheme. This 
allows composition
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
new file mode 100644
index 0000000..91a26c4
--- /dev/null
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixroute.go
@@ -0,0 +1,178 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+       "context"
+       "time"
+
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       scheme 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/scheme"
+       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       types "k8s.io/apimachinery/pkg/types"
+       watch "k8s.io/apimachinery/pkg/watch"
+       rest "k8s.io/client-go/rest"
+)
+
+// ApisixRoutesGetter has a method to return a ApisixRouteInterface.
+// A group's client should implement this interface.
+type ApisixRoutesGetter interface {
+       ApisixRoutes(namespace string) ApisixRouteInterface
+}
+
+// ApisixRouteInterface has methods to work with ApisixRoute resources.
+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)
+       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)
+       List(ctx context.Context, opts v1.ListOptions) 
(*v2alpha1.ApisixRouteList, error)
+       Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
+       Patch(ctx context.Context, name string, pt types.PatchType, data 
[]byte, opts v1.PatchOptions, subresources ...string) (result 
*v2alpha1.ApisixRoute, err error)
+       ApisixRouteExpansion
+}
+
+// apisixRoutes implements ApisixRouteInterface
+type apisixRoutes struct {
+       client rest.Interface
+       ns     string
+}
+
+// newApisixRoutes returns a ApisixRoutes
+func newApisixRoutes(c *ApisixV2alpha1Client, namespace string) *apisixRoutes {
+       return &apisixRoutes{
+               client: c.RESTClient(),
+               ns:     namespace,
+       }
+}
+
+// Get takes name of the apisixRoute, and returns the corresponding 
apisixRoute object, and an error if there is any.
+func (c *apisixRoutes) Get(ctx context.Context, name string, options 
v1.GetOptions) (result *v2alpha1.ApisixRoute, err error) {
+       result = &v2alpha1.ApisixRoute{}
+       err = c.client.Get().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               Name(name).
+               VersionedParams(&options, scheme.ParameterCodec).
+               Do(ctx).
+               Into(result)
+       return
+}
+
+// List takes label and field selectors, and returns the list of ApisixRoutes 
that match those selectors.
+func (c *apisixRoutes) List(ctx context.Context, opts v1.ListOptions) (result 
*v2alpha1.ApisixRouteList, err error) {
+       var timeout time.Duration
+       if opts.TimeoutSeconds != nil {
+               timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+       }
+       result = &v2alpha1.ApisixRouteList{}
+       err = c.client.Get().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               VersionedParams(&opts, scheme.ParameterCodec).
+               Timeout(timeout).
+               Do(ctx).
+               Into(result)
+       return
+}
+
+// Watch returns a watch.Interface that watches the requested apisixRoutes.
+func (c *apisixRoutes) Watch(ctx context.Context, opts v1.ListOptions) 
(watch.Interface, error) {
+       var timeout time.Duration
+       if opts.TimeoutSeconds != nil {
+               timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+       }
+       opts.Watch = true
+       return c.client.Get().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               VersionedParams(&opts, scheme.ParameterCodec).
+               Timeout(timeout).
+               Watch(ctx)
+}
+
+// Create takes the representation of a apisixRoute and creates it.  Returns 
the server's representation of the apisixRoute, and an error, if there is any.
+func (c *apisixRoutes) Create(ctx context.Context, apisixRoute 
*v2alpha1.ApisixRoute, opts v1.CreateOptions) (result *v2alpha1.ApisixRoute, 
err error) {
+       result = &v2alpha1.ApisixRoute{}
+       err = c.client.Post().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               VersionedParams(&opts, scheme.ParameterCodec).
+               Body(apisixRoute).
+               Do(ctx).
+               Into(result)
+       return
+}
+
+// Update takes the representation of a apisixRoute and updates it. Returns 
the server's representation of the apisixRoute, and an error, if there is any.
+func (c *apisixRoutes) Update(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).
+               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().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               Name(name).
+               Body(&opts).
+               Do(ctx).
+               Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *apisixRoutes) DeleteCollection(ctx context.Context, opts 
v1.DeleteOptions, listOpts v1.ListOptions) error {
+       var timeout time.Duration
+       if listOpts.TimeoutSeconds != nil {
+               timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
+       }
+       return c.client.Delete().
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               VersionedParams(&listOpts, scheme.ParameterCodec).
+               Timeout(timeout).
+               Body(&opts).
+               Do(ctx).
+               Error()
+}
+
+// Patch applies the patch and returns the patched apisixRoute.
+func (c *apisixRoutes) Patch(ctx context.Context, name string, pt 
types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) 
(result *v2alpha1.ApisixRoute, err error) {
+       result = &v2alpha1.ApisixRoute{}
+       err = c.client.Patch(pt).
+               Namespace(c.ns).
+               Resource("apisixroutes").
+               Name(name).
+               SubResource(subresources...).
+               VersionedParams(&opts, scheme.ParameterCodec).
+               Body(data).
+               Do(ctx).
+               Into(result)
+       return
+}
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/config_client.go
 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/config_client.go
new file mode 100644
index 0000000..ade8d12
--- /dev/null
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/config_client.go
@@ -0,0 +1,89 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/scheme"
+       rest "k8s.io/client-go/rest"
+)
+
+type ApisixV2alpha1Interface interface {
+       RESTClient() rest.Interface
+       ApisixRoutesGetter
+}
+
+// ApisixV2alpha1Client is used to interact with features provided by the 
apisix.apache.org group.
+type ApisixV2alpha1Client struct {
+       restClient rest.Interface
+}
+
+func (c *ApisixV2alpha1Client) ApisixRoutes(namespace string) 
ApisixRouteInterface {
+       return newApisixRoutes(c, namespace)
+}
+
+// NewForConfig creates a new ApisixV2alpha1Client for the given config.
+func NewForConfig(c *rest.Config) (*ApisixV2alpha1Client, error) {
+       config := *c
+       if err := setConfigDefaults(&config); err != nil {
+               return nil, err
+       }
+       client, err := rest.RESTClientFor(&config)
+       if err != nil {
+               return nil, err
+       }
+       return &ApisixV2alpha1Client{client}, nil
+}
+
+// NewForConfigOrDie creates a new ApisixV2alpha1Client for the given config 
and
+// panics if there is an error in the config.
+func NewForConfigOrDie(c *rest.Config) *ApisixV2alpha1Client {
+       client, err := NewForConfig(c)
+       if err != nil {
+               panic(err)
+       }
+       return client
+}
+
+// New creates a new ApisixV2alpha1Client for the given RESTClient.
+func New(c rest.Interface) *ApisixV2alpha1Client {
+       return &ApisixV2alpha1Client{c}
+}
+
+func setConfigDefaults(config *rest.Config) error {
+       gv := v2alpha1.SchemeGroupVersion
+       config.GroupVersion = &gv
+       config.APIPath = "/apis"
+       config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
+
+       if config.UserAgent == "" {
+               config.UserAgent = rest.DefaultKubernetesUserAgent()
+       }
+
+       return nil
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *ApisixV2alpha1Client) RESTClient() rest.Interface {
+       if c == nil {
+               return nil
+       }
+       return c.restClient
+}
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/doc.go 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/doc.go
new file mode 100644
index 0000000..3efe0d2
--- /dev/null
+++ b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated typed clients.
+package v2alpha1
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/doc.go 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/doc.go
new file mode 100644
index 0000000..16f4439
--- /dev/null
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// Package fake has the automatically generated clients.
+package fake
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
new file mode 100644
index 0000000..a57673b
--- /dev/null
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixroute.go
@@ -0,0 +1,130 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+       "context"
+
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       labels "k8s.io/apimachinery/pkg/labels"
+       schema "k8s.io/apimachinery/pkg/runtime/schema"
+       types "k8s.io/apimachinery/pkg/types"
+       watch "k8s.io/apimachinery/pkg/watch"
+       testing "k8s.io/client-go/testing"
+)
+
+// FakeApisixRoutes implements ApisixRouteInterface
+type FakeApisixRoutes struct {
+       Fake *FakeApisixV2alpha1
+       ns   string
+}
+
+var apisixroutesResource = schema.GroupVersionResource{Group: 
"apisix.apache.org", Version: "v2alpha1", Resource: "apisixroutes"}
+
+var apisixroutesKind = schema.GroupVersionKind{Group: "apisix.apache.org", 
Version: "v2alpha1", Kind: "ApisixRoute"}
+
+// Get takes name of the apisixRoute, and returns the corresponding 
apisixRoute object, and an error if there is any.
+func (c *FakeApisixRoutes) Get(ctx context.Context, name string, options 
v1.GetOptions) (result *v2alpha1.ApisixRoute, err error) {
+       obj, err := c.Fake.
+               Invokes(testing.NewGetAction(apisixroutesResource, c.ns, name), 
&v2alpha1.ApisixRoute{})
+
+       if obj == nil {
+               return nil, err
+       }
+       return obj.(*v2alpha1.ApisixRoute), err
+}
+
+// List takes label and field selectors, and returns the list of ApisixRoutes 
that match those selectors.
+func (c *FakeApisixRoutes) List(ctx context.Context, opts v1.ListOptions) 
(result *v2alpha1.ApisixRouteList, err error) {
+       obj, err := c.Fake.
+               Invokes(testing.NewListAction(apisixroutesResource, 
apisixroutesKind, c.ns, opts), &v2alpha1.ApisixRouteList{})
+
+       if obj == nil {
+               return nil, err
+       }
+
+       label, _, _ := testing.ExtractFromListOptions(opts)
+       if label == nil {
+               label = labels.Everything()
+       }
+       list := &v2alpha1.ApisixRouteList{ListMeta: 
obj.(*v2alpha1.ApisixRouteList).ListMeta}
+       for _, item := range obj.(*v2alpha1.ApisixRouteList).Items {
+               if label.Matches(labels.Set(item.Labels)) {
+                       list.Items = append(list.Items, item)
+               }
+       }
+       return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested apisixRoutes.
+func (c *FakeApisixRoutes) Watch(ctx context.Context, opts v1.ListOptions) 
(watch.Interface, error) {
+       return c.Fake.
+               InvokesWatch(testing.NewWatchAction(apisixroutesResource, c.ns, 
opts))
+
+}
+
+// Create takes the representation of a apisixRoute and creates it.  Returns 
the server's representation of the apisixRoute, and an error, if there is any.
+func (c *FakeApisixRoutes) Create(ctx context.Context, apisixRoute 
*v2alpha1.ApisixRoute, opts v1.CreateOptions) (result *v2alpha1.ApisixRoute, 
err error) {
+       obj, err := c.Fake.
+               Invokes(testing.NewCreateAction(apisixroutesResource, c.ns, 
apisixRoute), &v2alpha1.ApisixRoute{})
+
+       if obj == nil {
+               return nil, err
+       }
+       return obj.(*v2alpha1.ApisixRoute), err
+}
+
+// Update takes the representation of a apisixRoute and updates it. Returns 
the server's representation of the apisixRoute, and an error, if there is any.
+func (c *FakeApisixRoutes) Update(ctx context.Context, apisixRoute 
*v2alpha1.ApisixRoute, opts v1.UpdateOptions) (result *v2alpha1.ApisixRoute, 
err error) {
+       obj, err := c.Fake.
+               Invokes(testing.NewUpdateAction(apisixroutesResource, 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.
+               Invokes(testing.NewDeleteAction(apisixroutesResource, c.ns, 
name), &v2alpha1.ApisixRoute{})
+
+       return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeApisixRoutes) DeleteCollection(ctx context.Context, opts 
v1.DeleteOptions, listOpts v1.ListOptions) error {
+       action := testing.NewDeleteCollectionAction(apisixroutesResource, c.ns, 
listOpts)
+
+       _, err := c.Fake.Invokes(action, &v2alpha1.ApisixRouteList{})
+       return err
+}
+
+// Patch applies the patch and returns the patched apisixRoute.
+func (c *FakeApisixRoutes) Patch(ctx context.Context, name string, pt 
types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) 
(result *v2alpha1.ApisixRoute, err error) {
+       obj, err := c.Fake.
+               Invokes(testing.NewPatchSubresourceAction(apisixroutesResource, 
c.ns, name, pt, data, subresources...), &v2alpha1.ApisixRoute{})
+
+       if obj == nil {
+               return nil, err
+       }
+       return obj.(*v2alpha1.ApisixRoute), err
+}
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go
 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go
new file mode 100644
index 0000000..448bafe
--- /dev/null
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go
@@ -0,0 +1,40 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1"
+       rest "k8s.io/client-go/rest"
+       testing "k8s.io/client-go/testing"
+)
+
+type FakeApisixV2alpha1 struct {
+       *testing.Fake
+}
+
+func (c *FakeApisixV2alpha1) ApisixRoutes(namespace string) 
v2alpha1.ApisixRouteInterface {
+       return &FakeApisixRoutes{c, namespace}
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *FakeApisixV2alpha1) RESTClient() rest.Interface {
+       var ret *rest.RESTClient
+       return ret
+}
diff --git 
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go
 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go
new file mode 100644
index 0000000..980dad5
--- /dev/null
+++ 
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go
@@ -0,0 +1,21 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v2alpha1
+
+type ApisixRouteExpansion interface{}
diff --git 
a/pkg/kube/apisix/client/informers/externalversions/config/interface.go 
b/pkg/kube/apisix/client/informers/externalversions/config/interface.go
index 8dc3dca..c881109 100644
--- a/pkg/kube/apisix/client/informers/externalversions/config/interface.go
+++ b/pkg/kube/apisix/client/informers/externalversions/config/interface.go
@@ -20,6 +20,7 @@ package config
 
 import (
        v1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/config/v1"
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1"
        internalinterfaces 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/internalinterfaces"
 )
 
@@ -27,6 +28,8 @@ import (
 type Interface interface {
        // V1 provides access to shared informers for resources in V1.
        V1() v1.Interface
+       // V2alpha1 provides access to shared informers for resources in 
V2alpha1.
+       V2alpha1() v2alpha1.Interface
 }
 
 type group struct {
@@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, 
namespace string, tweakList
 func (g *group) V1() v1.Interface {
        return v1.New(g.factory, g.namespace, g.tweakListOptions)
 }
+
+// V2alpha1 returns a new v2alpha1.Interface.
+func (g *group) V2alpha1() v2alpha1.Interface {
+       return v2alpha1.New(g.factory, g.namespace, g.tweakListOptions)
+}
diff --git 
a/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/apisixroute.go
 
b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/apisixroute.go
new file mode 100644
index 0000000..b793bbf
--- /dev/null
+++ 
b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/apisixroute.go
@@ -0,0 +1,90 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+       "context"
+       time "time"
+
+       configv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       versioned 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned"
+       internalinterfaces 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/internalinterfaces"
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2alpha1"
+       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       runtime "k8s.io/apimachinery/pkg/runtime"
+       watch "k8s.io/apimachinery/pkg/watch"
+       cache "k8s.io/client-go/tools/cache"
+)
+
+// ApisixRouteInformer provides access to a shared informer and lister for
+// ApisixRoutes.
+type ApisixRouteInformer interface {
+       Informer() cache.SharedIndexInformer
+       Lister() v2alpha1.ApisixRouteLister
+}
+
+type apisixRouteInformer struct {
+       factory          internalinterfaces.SharedInformerFactory
+       tweakListOptions internalinterfaces.TweakListOptionsFunc
+       namespace        string
+}
+
+// NewApisixRouteInformer constructs a new informer for ApisixRoute type.
+// Always prefer using an informer factory to get a shared informer instead of 
getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewApisixRouteInformer(client versioned.Interface, namespace string, 
resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+       return NewFilteredApisixRouteInformer(client, namespace, resyncPeriod, 
indexers, nil)
+}
+
+// NewFilteredApisixRouteInformer constructs a new informer for ApisixRoute 
type.
+// Always prefer using an informer factory to get a shared informer instead of 
getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewFilteredApisixRouteInformer(client versioned.Interface, namespace 
string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions 
internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
+       return cache.NewSharedIndexInformer(
+               &cache.ListWatch{
+                       ListFunc: func(options v1.ListOptions) (runtime.Object, 
error) {
+                               if tweakListOptions != nil {
+                                       tweakListOptions(&options)
+                               }
+                               return 
client.ApisixV2alpha1().ApisixRoutes(namespace).List(context.TODO(), options)
+                       },
+                       WatchFunc: func(options v1.ListOptions) 
(watch.Interface, error) {
+                               if tweakListOptions != nil {
+                                       tweakListOptions(&options)
+                               }
+                               return 
client.ApisixV2alpha1().ApisixRoutes(namespace).Watch(context.TODO(), options)
+                       },
+               },
+               &configv2alpha1.ApisixRoute{},
+               resyncPeriod,
+               indexers,
+       )
+}
+
+func (f *apisixRouteInformer) defaultInformer(client versioned.Interface, 
resyncPeriod time.Duration) cache.SharedIndexInformer {
+       return NewFilteredApisixRouteInformer(client, f.namespace, 
resyncPeriod, cache.Indexers{cache.NamespaceIndex: 
cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *apisixRouteInformer) Informer() cache.SharedIndexInformer {
+       return f.factory.InformerFor(&configv2alpha1.ApisixRoute{}, 
f.defaultInformer)
+}
+
+func (f *apisixRouteInformer) Lister() v2alpha1.ApisixRouteLister {
+       return v2alpha1.NewApisixRouteLister(f.Informer().GetIndexer())
+}
diff --git 
a/pkg/kube/apisix/client/informers/externalversions/config/interface.go 
b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go
similarity index 68%
copy from pkg/kube/apisix/client/informers/externalversions/config/interface.go
copy to 
pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go
index 8dc3dca..620edb7 100644
--- a/pkg/kube/apisix/client/informers/externalversions/config/interface.go
+++ 
b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go
@@ -16,20 +16,19 @@ limitations under the License.
 
 // Code generated by informer-gen. DO NOT EDIT.
 
-package config
+package v2alpha1
 
 import (
-       v1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/config/v1"
        internalinterfaces 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/internalinterfaces"
 )
 
-// Interface provides access to each of this group's versions.
+// Interface provides access to all the informers in this group version.
 type Interface interface {
-       // V1 provides access to shared informers for resources in V1.
-       V1() v1.Interface
+       // ApisixRoutes returns a ApisixRouteInformer.
+       ApisixRoutes() ApisixRouteInformer
 }
 
-type group struct {
+type version struct {
        factory          internalinterfaces.SharedInformerFactory
        namespace        string
        tweakListOptions internalinterfaces.TweakListOptionsFunc
@@ -37,10 +36,10 @@ type group struct {
 
 // New returns a new Interface.
 func New(f internalinterfaces.SharedInformerFactory, namespace string, 
tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
-       return &group{factory: f, namespace: namespace, tweakListOptions: 
tweakListOptions}
+       return &version{factory: f, namespace: namespace, tweakListOptions: 
tweakListOptions}
 }
 
-// V1 returns a new v1.Interface.
-func (g *group) V1() v1.Interface {
-       return v1.New(g.factory, g.namespace, g.tweakListOptions)
+// ApisixRoutes returns a ApisixRouteInformer.
+func (v *version) ApisixRoutes() ApisixRouteInformer {
+       return &apisixRouteInformer{factory: v.factory, namespace: v.namespace, 
tweakListOptions: v.tweakListOptions}
 }
diff --git a/pkg/kube/apisix/client/informers/externalversions/generic.go 
b/pkg/kube/apisix/client/informers/externalversions/generic.go
index ffd2686..8c2e73e 100644
--- a/pkg/kube/apisix/client/informers/externalversions/generic.go
+++ b/pkg/kube/apisix/client/informers/externalversions/generic.go
@@ -22,6 +22,7 @@ import (
        "fmt"
 
        v1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
        schema "k8s.io/apimachinery/pkg/runtime/schema"
        cache "k8s.io/client-go/tools/cache"
 )
@@ -60,6 +61,10 @@ func (f *sharedInformerFactory) ForResource(resource 
schema.GroupVersionResource
        case v1.SchemeGroupVersion.WithResource("apisixupstreams"):
                return &genericInformer{resource: resource.GroupResource(), 
informer: f.Apisix().V1().ApisixUpstreams().Informer()}, nil
 
+               // Group=apisix.apache.org, Version=v2alpha1
+       case v2alpha1.SchemeGroupVersion.WithResource("apisixroutes"):
+               return &genericInformer{resource: resource.GroupResource(), 
informer: f.Apisix().V2alpha1().ApisixRoutes().Informer()}, nil
+
        }
 
        return nil, fmt.Errorf("no informer found for %v", resource)
diff --git a/pkg/kube/apisix/client/listers/config/v2alpha1/apisixroute.go 
b/pkg/kube/apisix/client/listers/config/v2alpha1/apisixroute.go
new file mode 100644
index 0000000..687e227
--- /dev/null
+++ b/pkg/kube/apisix/client/listers/config/v2alpha1/apisixroute.go
@@ -0,0 +1,99 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+       v2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       "k8s.io/apimachinery/pkg/api/errors"
+       "k8s.io/apimachinery/pkg/labels"
+       "k8s.io/client-go/tools/cache"
+)
+
+// ApisixRouteLister helps list ApisixRoutes.
+// All objects returned here must be treated as read-only.
+type ApisixRouteLister interface {
+       // List lists all ApisixRoutes in the indexer.
+       // Objects returned here must be treated as read-only.
+       List(selector labels.Selector) (ret []*v2alpha1.ApisixRoute, err error)
+       // ApisixRoutes returns an object that can list and get ApisixRoutes.
+       ApisixRoutes(namespace string) ApisixRouteNamespaceLister
+       ApisixRouteListerExpansion
+}
+
+// apisixRouteLister implements the ApisixRouteLister interface.
+type apisixRouteLister struct {
+       indexer cache.Indexer
+}
+
+// NewApisixRouteLister returns a new ApisixRouteLister.
+func NewApisixRouteLister(indexer cache.Indexer) ApisixRouteLister {
+       return &apisixRouteLister{indexer: indexer}
+}
+
+// List lists all ApisixRoutes in the indexer.
+func (s *apisixRouteLister) List(selector labels.Selector) (ret 
[]*v2alpha1.ApisixRoute, err error) {
+       err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+               ret = append(ret, m.(*v2alpha1.ApisixRoute))
+       })
+       return ret, err
+}
+
+// ApisixRoutes returns an object that can list and get ApisixRoutes.
+func (s *apisixRouteLister) ApisixRoutes(namespace string) 
ApisixRouteNamespaceLister {
+       return apisixRouteNamespaceLister{indexer: s.indexer, namespace: 
namespace}
+}
+
+// ApisixRouteNamespaceLister helps list and get ApisixRoutes.
+// All objects returned here must be treated as read-only.
+type ApisixRouteNamespaceLister interface {
+       // List lists all ApisixRoutes in the indexer for a given namespace.
+       // Objects returned here must be treated as read-only.
+       List(selector labels.Selector) (ret []*v2alpha1.ApisixRoute, err error)
+       // Get retrieves the ApisixRoute from the indexer for a given namespace 
and name.
+       // Objects returned here must be treated as read-only.
+       Get(name string) (*v2alpha1.ApisixRoute, error)
+       ApisixRouteNamespaceListerExpansion
+}
+
+// apisixRouteNamespaceLister implements the ApisixRouteNamespaceLister
+// interface.
+type apisixRouteNamespaceLister struct {
+       indexer   cache.Indexer
+       namespace string
+}
+
+// List lists all ApisixRoutes in the indexer for a given namespace.
+func (s apisixRouteNamespaceLister) List(selector labels.Selector) (ret 
[]*v2alpha1.ApisixRoute, err error) {
+       err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m 
interface{}) {
+               ret = append(ret, m.(*v2alpha1.ApisixRoute))
+       })
+       return ret, err
+}
+
+// Get retrieves the ApisixRoute from the indexer for a given namespace and 
name.
+func (s apisixRouteNamespaceLister) Get(name string) (*v2alpha1.ApisixRoute, 
error) {
+       obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
+       if err != nil {
+               return nil, err
+       }
+       if !exists {
+               return nil, 
errors.NewNotFound(v2alpha1.Resource("apisixroute"), name)
+       }
+       return obj.(*v2alpha1.ApisixRoute), nil
+}
diff --git 
a/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go 
b/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go
new file mode 100644
index 0000000..e26b85d
--- /dev/null
+++ b/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go
@@ -0,0 +1,27 @@
+/*
+Copyright The Kubernetes 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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+package v2alpha1
+
+// ApisixRouteListerExpansion allows custom methods to be added to
+// ApisixRouteLister.
+type ApisixRouteListerExpansion interface{}
+
+// ApisixRouteNamespaceListerExpansion allows custom methods to be added to
+// ApisixRouteNamespaceLister.
+type ApisixRouteNamespaceListerExpansion interface{}
diff --git a/pkg/kube/apisix_route.go b/pkg/kube/apisix_route.go
new file mode 100644
index 0000000..0cd6bc5
--- /dev/null
+++ b/pkg/kube/apisix_route.go
@@ -0,0 +1,175 @@
+// 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 kube
+
+import (
+       "errors"
+
+       configv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
+       configv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       listersv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v1"
+       listersv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2alpha1"
+)
+
+const (
+       // ApisixRouteV1 represents the ApisixRoute in apisix.apache.org/v1 
group version.
+       ApisixRouteV1 = "apisix.apache.org/v1"
+       // ApisixRouteV2alpha1 represents the APisixRoute in 
apisix.apache.org/v2alpha1 group version
+       ApisixRouteV2alpha1 = "apisix.apache.org/v2alpha1"
+)
+
+// ApisixRouteLister is an encapsulation for the lister of ApisixRoute,
+// it aims at to be compatible with different ApisixRoute versions.
+type ApisixRouteLister interface {
+       // V1 gets the ApisixRoute in apisix.apache.org/v1.
+       V1(string, string) (ApisixRoute, error)
+       // V2alpha1 gets the ApisixRoute in apisix.apache.org/v2alpha1.
+       V2alpha1(string, string) (ApisixRoute, error)
+}
+
+// ApisixRouteInformer is an encapsulation for the informer of ApisixRoute,
+// it aims at to be compatible with different ApisixRoute versions.
+type ApisixRouteInformer interface {
+       Run(chan struct{})
+}
+
+// ApisixRoute is an encapsulation for ApisixRoute resource with different
+// versions, for now, they are apisix.apache.org/v1 and 
apisix.apache.org/v2alpha1
+type ApisixRoute interface {
+       // GroupVersion returns the api group version of the
+       // real ApisixRoute.
+       GroupVersion() string
+       // V1 returns the ApisixRoute in apisix.apache.org/v1, the real
+       // ApisixRoute must be in this group version, or V1() will panic.
+       V1() *configv1.ApisixRoute
+       // V2alpha1 returns the ApisixRoute in apisix.apache.org/v1alpha1, the 
real
+       // ApisixRoute must be in this group version, or V2alpha1() will panic.
+       V2alpha1() *configv2alpha1.ApisixRoute
+       // ResourceVersion returns the the resource version field inside
+       // the real ApisixRoute.
+       ResourceVersion() string
+}
+
+// ApisixRouteEvent contains the ApisixRoute key (namespace/name)
+// and the group version message.
+type ApisixRouteEvent struct {
+       Key          string
+       OldObject    ApisixRoute
+       GroupVersion string
+}
+
+type apisixRoute struct {
+       groupVersion string
+       v1           *configv1.ApisixRoute
+       v2alpha1     *configv2alpha1.ApisixRoute
+}
+
+func (ar *apisixRoute) V1() *configv1.ApisixRoute {
+       if ar.groupVersion != ApisixRouteV1 {
+               panic("not a apisix.apache.org/v1 ingress")
+       }
+       return ar.v1
+}
+
+func (ar *apisixRoute) V2alpha1() *configv2alpha1.ApisixRoute {
+       if ar.groupVersion != ApisixRouteV2alpha1 {
+               panic("not a apisix.apache.org/v2alpha1 ingress")
+       }
+       return ar.v2alpha1
+}
+
+func (ar *apisixRoute) GroupVersion() string {
+       return ar.groupVersion
+}
+
+func (ar *apisixRoute) ResourceVersion() string {
+       if ar.groupVersion == ApisixRouteV1 {
+               return ar.V1().ResourceVersion
+       }
+       return ar.V2alpha1().ResourceVersion
+}
+
+type apisixRouteLister struct {
+       v1Lister       listersv1.ApisixRouteLister
+       v2alpha1Lister listersv2alpha1.ApisixRouteLister
+}
+
+func (l *apisixRouteLister) V1(namespace, name string) (ApisixRoute, error) {
+       ar, err := l.v1Lister.ApisixRoutes(namespace).Get(name)
+       if err != nil {
+               return nil, err
+       }
+       return &apisixRoute{
+               groupVersion: ApisixRouteV1,
+               v1:           ar,
+       }, nil
+}
+
+func (l *apisixRouteLister) V2alpha1(namespace, name string) (ApisixRoute, 
error) {
+       ar, err := l.v2alpha1Lister.ApisixRoutes(namespace).Get(name)
+       if err != nil {
+               return nil, err
+       }
+       return &apisixRoute{
+               groupVersion: ApisixRouteV2alpha1,
+               v2alpha1:     ar,
+       }, nil
+}
+
+// MustNewApisixRoute creates a kube.ApisixRoute object according to the
+// type of obj.
+func MustNewApisixRoute(obj interface{}) ApisixRoute {
+       switch ar := obj.(type) {
+       case *configv1.ApisixRoute:
+               return &apisixRoute{
+                       groupVersion: ApisixRouteV1,
+                       v1:           ar,
+               }
+       case *configv2alpha1.ApisixRoute:
+               return &apisixRoute{
+                       groupVersion: ApisixRouteV2alpha1,
+                       v2alpha1:     ar,
+               }
+       default:
+               panic("invalid ApisixRoute type")
+       }
+}
+
+// NewApisixRoute creates a kube.ApisixRoute object according to the
+// type of obj. It returns nil and the error reason when the
+// type assertion fails.
+func NewApisixRoute(obj interface{}) (ApisixRoute, error) {
+       switch ar := obj.(type) {
+       case *configv1.ApisixRoute:
+               return &apisixRoute{
+                       groupVersion: ApisixRouteV1,
+                       v1:           ar,
+               }, nil
+       case *configv2alpha1.ApisixRoute:
+               return &apisixRoute{
+                       groupVersion: ApisixRouteV2alpha1,
+                       v2alpha1:     ar,
+               }, nil
+       default:
+               return nil, errors.New("invalid ApisixRoute type")
+       }
+}
+
+func NewApisixRouteLister(v1 listersv1.ApisixRouteLister, v2alpha1 
listersv2alpha1.ApisixRouteLister) ApisixRouteLister {
+       return &apisixRouteLister{
+               v1Lister:       v1,
+               v2alpha1Lister: v2alpha1,
+       }
+}
diff --git a/pkg/kube/translation/apisix_route.go 
b/pkg/kube/translation/apisix_route.go
index a7909e1..ab61048 100644
--- a/pkg/kube/translation/apisix_route.go
+++ b/pkg/kube/translation/apisix_route.go
@@ -15,8 +15,15 @@
 package translation
 
 import (
+       "errors"
+
+       "go.uber.org/zap"
+       "k8s.io/apimachinery/pkg/util/intstr"
+
        "github.com/apache/apisix-ingress-controller/pkg/id"
        configv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
+       configv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
+       "github.com/apache/apisix-ingress-controller/pkg/log"
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
@@ -84,3 +91,113 @@ func (t *translator) TranslateRouteV1(ar 
*configv1.ApisixRoute) ([]*apisixv1.Rou
        }
        return routes, upstreams, nil
 }
+
+func (t *translator) TranslateRouteV2alpha1(ar *configv2alpha1.ApisixRoute) 
([]*apisixv1.Route, []*apisixv1.Upstream, error) {
+       var (
+               routes    []*apisixv1.Route
+               upstreams []*apisixv1.Upstream
+       )
+
+       upstreamMap := make(map[string]*apisixv1.Upstream)
+
+       for _, part := range ar.Spec.HTTP {
+               if part.Match == nil {
+                       return nil, nil, errors.New("empty route match section")
+               }
+               if len(part.Match.Paths) < 1 {
+                       return nil, nil, errors.New("empty route paths match")
+               }
+               svc, err := 
t.ServiceLister.Services(ar.Namespace).Get(part.Backend.ServiceName)
+               if err != nil {
+                       return nil, nil, err
+               }
+               svcPort := int32(-1)
+       loop:
+               for _, port := range svc.Spec.Ports {
+                       switch part.Backend.ServicePort.Type {
+                       case intstr.Int:
+                               if part.Backend.ServicePort.IntVal == port.Port 
{
+                                       svcPort = port.Port
+                                       break loop
+                               }
+                       case intstr.String:
+                               if part.Backend.ServicePort.StrVal == port.Name 
{
+                                       svcPort = port.Port
+                                       break loop
+                               }
+                       }
+               }
+               if svcPort == -1 {
+                       log.Errorw("ApisixRoute refers to non-existent Service 
port",
+                               zap.Any("ApisixRoute", ar),
+                               zap.String("port", 
part.Backend.ServicePort.String()),
+                       )
+                       return nil, nil, err
+               }
+
+               if part.Backend.ResolveGranularity == "service" && 
svc.Spec.ClusterIP == "" {
+                       log.Errorw("ApisixRoute refers to a headless service 
but want to use the service level resolve granualrity",
+                               zap.Any("ApisixRoute", ar),
+                               zap.Any("service", svc),
+                       )
+                       return nil, nil, errors.New("conflict headless service 
and backend resolve granularity")
+               }
+
+               pluginMap := make(apisixv1.Plugins)
+               // 2.add route plugins
+               for _, plugin := range part.Plugins {
+                       if !plugin.Enable {
+                               continue
+                       }
+                       if plugin.Config != nil {
+                               pluginMap[plugin.Name] = plugin.Config
+                       } else {
+                               pluginMap[plugin.Name] = 
make(map[string]interface{})
+                       }
+               }
+
+               routeName := apisixv1.ComposeRouteName(ar.Namespace, ar.Name, 
part.Name)
+               upstreamName := apisixv1.ComposeUpstreamName(ar.Namespace, 
part.Backend.ServiceName, svcPort)
+               route := &apisixv1.Route{
+                       Metadata: apisixv1.Metadata{
+                               FullName:        routeName,
+                               Name:            routeName,
+                               ID:              id.GenID(routeName),
+                               ResourceVersion: ar.ResourceVersion,
+                       },
+                       Hosts:        part.Match.Hosts,
+                       Uris:         part.Match.Paths,
+                       Methods:      part.Match.Methods,
+                       UpstreamName: upstreamName,
+                       UpstreamId:   id.GenID(upstreamName),
+                       Plugins:      pluginMap,
+               }
+
+               routes = append(routes, route)
+
+               if _, ok := upstreamMap[upstreamName]; !ok {
+                       ups, err := t.TranslateUpstream(ar.Namespace, 
part.Backend.ServiceName, svcPort)
+                       if err != nil {
+                               return nil, nil, err
+                       }
+                       if part.Backend.ResolveGranularity == "service" {
+                               ups.Nodes = []apisixv1.UpstreamNode{
+                                       {
+                                               IP:     svc.Spec.ClusterIP,
+                                               Port:   int(svcPort),
+                                               Weight: _defaultWeight,
+                                       },
+                               }
+                       }
+                       ups.FullName = upstreamName
+                       ups.ResourceVersion = ar.ResourceVersion
+                       ups.Name = upstreamName
+                       upstreamMap[ups.FullName] = ups
+               }
+       }
+
+       for _, ups := range upstreamMap {
+               upstreams = append(upstreams, ups)
+       }
+       return routes, upstreams, nil
+}
diff --git a/pkg/kube/translation/translator.go 
b/pkg/kube/translation/translator.go
index da31d20..f7843b6 100644
--- a/pkg/kube/translation/translator.go
+++ b/pkg/kube/translation/translator.go
@@ -23,6 +23,7 @@ import (
 
        "github.com/apache/apisix-ingress-controller/pkg/kube"
        configv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1"
+       configv2alpha1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
        listersv1 
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v1"
        apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
@@ -60,6 +61,9 @@ type Translator interface {
        // TranslateRouteV1 translates the configv1.ApisixRoute object into 
several Route
        // and Upstream resources.
        TranslateRouteV1(*configv1.ApisixRoute) ([]*apisixv1.Route, 
[]*apisixv1.Upstream, error)
+       // TranslateRouteV2alpha1 translates the configv2alph1.ApisixRoute 
object into several Route
+       // and Upstream resources.
+       TranslateRouteV2alpha1(*configv2alpha1.ApisixRoute) ([]*apisixv1.Route, 
[]*apisixv1.Upstream, error)
 }
 
 // TranslatorOptions contains options to help Translator
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index 638858c..57eaf4c 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -82,7 +82,9 @@ type Route struct {
        Metadata `json:",inline" yaml:",inline"`
 
        Host         string   `json:"host,omitempty" yaml:"host,omitempty"`
+       Hosts        []string `json:"hosts,omitempty" yaml:"hosts,omitempty"`
        Path         string   `json:"path,omitempty" yaml:"path,omitempty"`
+       Priority     int      `json:"priority,omitempty" 
yaml:"priority,omitempty"`
        Uris         []string `json:"uris,omitempty" yaml:"uris,omitempty"`
        Methods      []string `json:"methods,omitempty" 
yaml:"methods,omitempty"`
        ServiceId    string   `json:"service_id,omitempty" 
yaml:"service_id,omitempty"`
@@ -264,3 +266,20 @@ func ComposeUpstreamName(namespace, name string, port 
int32) string {
 
        return buf.String()
 }
+
+// ComposeRouteName uses namespace, name and rule name to compose
+// the route name.
+func ComposeRouteName(namespace, name string, rule string) string {
+       // FIXME Use sync.Pool to reuse this buffer if the upstream
+       // name composing code path is hot.
+       p := make([]byte, 0, len(namespace)+len(name)+len(rule)+2)
+       buf := bytes.NewBuffer(p)
+
+       buf.WriteString(namespace)
+       buf.WriteByte('_')
+       buf.WriteString(name)
+       buf.WriteByte('_')
+       buf.WriteString(rule)
+
+       return buf.String()
+}
diff --git a/pkg/types/apisix/v1/zz_generated.deepcopy.go 
b/pkg/types/apisix/v1/zz_generated.deepcopy.go
index 51869da..d914f5e 100644
--- a/pkg/types/apisix/v1/zz_generated.deepcopy.go
+++ b/pkg/types/apisix/v1/zz_generated.deepcopy.go
@@ -24,6 +24,16 @@ package v1
 func (in *Route) DeepCopyInto(out *Route) {
        *out = *in
        out.Metadata = in.Metadata
+       if in.Hosts != nil {
+               in, out := &in.Hosts, &out.Hosts
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       if in.Uris != nil {
+               in, out := &in.Uris, &out.Uris
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
        if in.Methods != nil {
                in, out := &in.Methods, &out.Methods
                *out = make([]string, len(*in))
diff --git a/samples/deploy/crd/v1beta1/ApisixRoute.yaml 
b/samples/deploy/crd/v1beta1/ApisixRoute.yaml
index a4e495d..af70902 100644
--- a/samples/deploy/crd/v1beta1/ApisixRoute.yaml
+++ b/samples/deploy/crd/v1beta1/ApisixRoute.yaml
@@ -24,6 +24,9 @@ spec:
   versions:
     - name: v1
       served: true
+      storage: false
+    - name: v2alpha1
+      served: true
       storage: true
   scope: Namespaced
   names:
diff --git a/test/e2e/endpoints/endpoints.go b/test/e2e/endpoints/endpoints.go
index 86a1ff2..8cc2c4f 100644
--- a/test/e2e/endpoints/endpoints.go
+++ b/test/e2e/endpoints/endpoints.go
@@ -105,7 +105,7 @@ spec:
        path: /ip
 `, backendSvc, backendSvcPort[0])
                assert.Nil(ginkgo.GinkgoT(), 
s.CreateResourceFromString(apisixRoute))
-               time.Sleep(3 * time.Second)
+               time.Sleep(5 * time.Second)
                ups, err := s.ListApisixUpstreams()
                assert.Nil(ginkgo.GinkgoT(), err, "listing APISIX upstreams")
                assert.Len(ginkgo.GinkgoT(), ups, 1)
diff --git a/test/e2e/go.mod b/test/e2e/go.mod
index 65d7d26..3fc8e00 100644
--- a/test/e2e/go.mod
+++ b/test/e2e/go.mod
@@ -4,8 +4,8 @@ go 1.14
 
 require (
        github.com/apache/apisix-ingress-controller 
v0.0.0-20210105024109-72e53386de5a
-       github.com/gavv/httpexpect/v2 v2.1.0
-       github.com/gruntwork-io/terratest v0.32.7
+       github.com/gavv/httpexpect/v2 v2.2.0
+       github.com/gruntwork-io/terratest v0.32.8
        github.com/onsi/ginkgo v1.14.2
        github.com/stretchr/testify v1.6.1
        k8s.io/api v0.20.2
diff --git a/test/e2e/go.sum b/test/e2e/go.sum
index 1bb3ed4..a32c64a 100644
--- a/test/e2e/go.sum
+++ b/test/e2e/go.sum
@@ -72,12 +72,16 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod 
h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
 github.com/PuerkitoBio/purell v1.1.1/go.mod 
h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod 
h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod 
h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/agext/levenshtein v1.2.1/go.mod 
h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
 github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
 github.com/ajg/form v1.5.1/go.mod 
h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod 
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod 
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod 
h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
+github.com/apparentlymart/go-textseg v1.0.0/go.mod 
h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
+github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod 
h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod 
h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod 
h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod 
h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -168,6 +172,8 @@ github.com/fsnotify/fsnotify v1.4.9 
h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
 github.com/fsnotify/fsnotify v1.4.9/go.mod 
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/gavv/httpexpect/v2 v2.1.0 
h1:Q7xnFuKqBY2si4DsqxdbWBt9rfrbVTT2/9YSomc9tEw=
 github.com/gavv/httpexpect/v2 v2.1.0/go.mod 
h1:lnd0TqJLrP+wkJk3SFwtrpSlOAZQ7HaaIFuOYbgqgUM=
+github.com/gavv/httpexpect/v2 v2.2.0 
h1:0VwaEBmQaNFHX9x591A8Up+8shCwdF/nF0qlRd/nI48=
+github.com/gavv/httpexpect/v2 v2.2.0/go.mod 
h1:lnd0TqJLrP+wkJk3SFwtrpSlOAZQ7HaaIFuOYbgqgUM=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gin-contrib/sse v0.1.0/go.mod 
h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
@@ -203,6 +209,7 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod 
h1:uOYAAleCW8F/7oMFd6aG0GO
 github.com/go-sql-driver/mysql v1.4.1 
h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
 github.com/go-sql-driver/mysql v1.4.1/go.mod 
h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-test/deep v1.0.3/go.mod 
h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/gogo/protobuf v1.1.1/go.mod 
h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod 
h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod 
h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -221,6 +228,7 @@ github.com/golang/mock v1.3.1/go.mod 
h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
 github.com/golang/mock v1.4.0/go.mod 
h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.1/go.mod 
h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.1.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -297,6 +305,8 @@ github.com/gruntwork-io/terratest v0.32.3 
h1:GSe/mkSQe0rD7Z92NKTUjDKg2FBuy0w82Tt
 github.com/gruntwork-io/terratest v0.32.3/go.mod 
h1:PlvB/MeCTUE9gX2Eabx/GAFjfuFL8kR8gfwxxn2B15Q=
 github.com/gruntwork-io/terratest v0.32.7 
h1:TJF4ZyOviWknlmzgre48JGGoXa20S8Ng0O/sfBfH+Bw=
 github.com/gruntwork-io/terratest v0.32.7/go.mod 
h1:0iy7d56CziX3R4ZUn570HMElr4WgBKoKNa8Hzex7bvo=
+github.com/gruntwork-io/terratest v0.32.8 
h1:ccIRFH+e6zhSB5difg7baJec4FeOZNXpeIFlZZlKW2M=
+github.com/gruntwork-io/terratest v0.32.8/go.mod 
h1:FckR+7ks472IJfSKUPfPvnJfSxV1LKGWGMJ9m/LHegE=
 github.com/hashicorp/consul/api v1.1.0/go.mod 
h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod 
h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0 
h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -323,6 +333,7 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod 
h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.3 
h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
 github.com/hashicorp/golang-lru v0.5.3/go.mod 
h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod 
h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcl/v2 v2.8.2/go.mod 
h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
 github.com/hashicorp/logutils v1.0.0/go.mod 
h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod 
h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod 
h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
@@ -374,6 +385,7 @@ github.com/kr/pty v1.1.1/go.mod 
h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod 
h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
 github.com/leodido/go-urn v1.2.0/go.mod 
h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/magiconair/properties v1.8.0/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -405,6 +417,7 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
 github.com/mitchellh/go-homedir v1.1.0 
h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod 
h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod 
h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/gox v0.4.0/go.mod 
h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -513,6 +526,7 @@ github.com/spf13/cobra v1.1.1/go.mod 
h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJ
 github.com/spf13/jwalterweatherman v1.0.0/go.mod 
h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.2/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -543,6 +557,7 @@ github.com/valyala/fasthttp v1.9.0 
h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrM
 github.com/valyala/fasthttp v1.9.0/go.mod 
h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
 github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod 
h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
 github.com/vdemeester/k8s-pkg-credentialprovider 
v0.0.0-20200107171650-7c61ffa44238/go.mod 
h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod 
h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
 github.com/vmware/govmomi v0.20.3/go.mod 
h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f 
h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod 
h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -561,6 +576,7 @@ github.com/yudai/golcs 
v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf
 github.com/yudai/pp v2.0.1+incompatible 
h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
 github.com/yudai/pp v2.0.1+incompatible/go.mod 
h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
 github.com/yuin/goldmark v1.1.27/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zclconf/go-cty v1.2.0/go.mod 
h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod 
h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
@@ -585,6 +601,7 @@ golang.org/x/crypto 
v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 
h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -633,6 +650,7 @@ golang.org/x/mod v0.3.0 
h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -697,6 +715,7 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod 
h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/test/e2e/ingress/resourcepushing.go 
b/test/e2e/ingress/resourcepushing.go
index a936c45..7e590e7 100644
--- a/test/e2e/ingress/resourcepushing.go
+++ b/test/e2e/ingress/resourcepushing.go
@@ -26,23 +26,35 @@ import (
 )
 
 var _ = ginkgo.Describe("ApisixRoute Testing", func() {
-       s := scaffold.NewDefaultScaffold()
+
+       opts := &scaffold.Options{
+               Name:                    "default",
+               Kubeconfig:              scaffold.GetKubeconfig(),
+               APISIXConfigPath:        "testdata/apisix-gw-config.yaml",
+               APISIXDefaultConfigPath: 
"testdata/apisix-gw-config-default.yaml",
+               IngressAPISIXReplicas:   1,
+               HTTPBinServicePort:      80,
+               APISIXRouteVersion:      "apisix.apache.org/v2alpha1",
+       }
+       s := scaffold.NewScaffold(opts)
        ginkgo.It("create and then scale upstream pods to 2 ", func() {
                backendSvc, backendSvcPort := s.DefaultHTTPBackend()
                apisixRoute := fmt.Sprintf(`
-apiVersion: apisix.apache.org/v1
+apiVersion: apisix.apache.org/v2alpha1
 kind: ApisixRoute
 metadata:
   name: httpbin-route
 spec:
-  rules:
-  - host: httpbin.com
-    http:
+  http:
+  - name: rule1
+    match:
+      hosts:
+      - httpbin.com
       paths:
-      - backend:
-          serviceName: %s
-          servicePort: %d
-        path: /ip
+      - /ip
+    backend:
+      serviceName: %s
+      servicePort: %d
 `, backendSvc, backendSvcPort[0])
                assert.Nil(ginkgo.GinkgoT(), 
s.CreateResourceFromString(apisixRoute))
 
@@ -64,19 +76,21 @@ spec:
        ginkgo.It("create and then remove", func() {
                backendSvc, backendSvcPort := s.DefaultHTTPBackend()
                apisixRoute := fmt.Sprintf(`
-apiVersion: apisix.apache.org/v1
+apiVersion: apisix.apache.org/v2alpha1
 kind: ApisixRoute
 metadata:
   name: httpbin-route
 spec:
-  rules:
-  - host: httpbin.com
-    http:
+  http:
+  - name: rule1
+    match:
+      hosts:
+      - httpbin.com
       paths:
-      - backend:
-          serviceName: %s
-          servicePort: %d
-        path: /ip
+      - /ip
+    backend:
+      serviceName: %s
+      servicePort: %d
 `, backendSvc, backendSvcPort[0])
 
                assert.Nil(ginkgo.GinkgoT(), 
s.CreateResourceFromString(apisixRoute), "creating ApisixRoute")
diff --git a/test/e2e/scaffold/ingress.go b/test/e2e/scaffold/ingress.go
index eb7cc91..b3cb70f 100644
--- a/test/e2e/scaffold/ingress.go
+++ b/test/e2e/scaffold/ingress.go
@@ -247,12 +247,14 @@ spec:
             - http://apisix-service-e2e-test:9180/apisix/admin
             - --app-namespace
             - %s
+            - --apisix-route-version
+            - %s
       serviceAccount: ingress-apisix-e2e-test-service-account
 `
 )
 
 func (s *Scaffold) newIngressAPISIXController() error {
-       ingressAPISIXDeployment := 
fmt.Sprintf(_ingressAPISIXDeploymentTemplate, s.opts.IngressAPISIXReplicas, 
s.namespace)
+       ingressAPISIXDeployment := 
fmt.Sprintf(_ingressAPISIXDeploymentTemplate, s.opts.IngressAPISIXReplicas, 
s.namespace, s.opts.APISIXRouteVersion)
        if err := k8s.CreateServiceAccountE(s.t, s.kubectlOptions, 
_serviceAccount); err != nil {
                return err
        }
diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go
index 5ab61c8..ed2979a 100644
--- a/test/e2e/scaffold/scaffold.go
+++ b/test/e2e/scaffold/scaffold.go
@@ -28,6 +28,7 @@ import (
        "text/template"
        "time"
 
+       "github.com/apache/apisix-ingress-controller/pkg/kube"
        "github.com/gavv/httpexpect/v2"
        "github.com/gruntwork-io/terratest/modules/k8s"
        "github.com/gruntwork-io/terratest/modules/testing"
@@ -46,6 +47,7 @@ type Options struct {
        APISIXDefaultConfigPath string
        IngressAPISIXReplicas   int
        HTTPBinServicePort      int
+       APISIXRouteVersion      string
 }
 
 type Scaffold struct {
@@ -86,6 +88,9 @@ func GetKubeconfig() string {
 
 // NewScaffold creates an e2e test scaffold.
 func NewScaffold(o *Options) *Scaffold {
+       if o.APISIXRouteVersion == "" {
+               o.APISIXRouteVersion = kube.ApisixRouteV1
+       }
        defer ginkgo.GinkgoRecover()
 
        s := &Scaffold{
@@ -108,6 +113,7 @@ func NewDefaultScaffold() *Scaffold {
                APISIXDefaultConfigPath: 
"testdata/apisix-gw-config-default.yaml",
                IngressAPISIXReplicas:   1,
                HTTPBinServicePort:      80,
+               APISIXRouteVersion:      kube.ApisixRouteV1,
        }
        return NewScaffold(opts)
 }

Reply via email to