You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by zh...@apache.org on 2022/05/23 09:10:01 UTC

[apisix-ingress-controller] branch master updated: feat: support ApisixConsumer v2 (#989)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new f6f0a3b5 feat: support ApisixConsumer v2 (#989)
f6f0a3b5 is described below

commit f6f0a3b5552ba8fda556e0edb9296c1c0a4c3e31
Author: Sarasa Kisaragi <li...@gmail.com>
AuthorDate: Mon May 23 17:09:56 2022 +0800

    feat: support ApisixConsumer v2 (#989)
---
 cmd/ingress/ingress.go                       |   1 +
 pkg/config/config.go                         |   2 +
 pkg/config/config_test.go                    |   2 +
 pkg/ingress/apisix_consumer.go               | 158 ++++++++++++++++++-------
 pkg/ingress/compare.go                       |   2 +-
 pkg/ingress/controller.go                    |  17 ++-
 pkg/ingress/status.go                        |  17 +++
 pkg/kube/apisix_consumer.go                  | 169 +++++++++++++++++++++++++++
 pkg/kube/translation/apisix_consumer.go      |  48 +++++++-
 pkg/kube/translation/apisix_consumer_test.go | 116 +++++++++++++++++-
 pkg/kube/translation/plugin.go               | 123 ++++++++++++++++++-
 pkg/kube/translation/plugin_test.go          |  54 ++++-----
 pkg/kube/translation/translator.go           |   7 +-
 13 files changed, 630 insertions(+), 86 deletions(-)

diff --git a/cmd/ingress/ingress.go b/cmd/ingress/ingress.go
index d0a24be5..daed1637 100644
--- a/cmd/ingress/ingress.go
+++ b/cmd/ingress/ingress.go
@@ -164,6 +164,7 @@ For example, no available LB exists in the bare metal environment.`)
 	cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ApisixRouteVersion, "apisix-route-version", config.ApisixRouteV2beta3, "the supported apisixroute api group version, can be \"apisix.apache.org/v2beta2\" or \"apisix.apache.org/v2beta3\"")
 	cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ApisixTlsVersion, "apisix-tls-version", config.ApisixV2beta3, "the supported apisixtls api group version, can be \"apisix.apache.org/v2beta3\" or \"apisix.apache.org/v2\"")
 	cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ApisixClusterConfigVersion, "apisix-cluster-config-version", config.ApisixV2beta3, "the supported ApisixClusterConfig api group version, can be \"apisix.apache.org/v2beta3\" or \"apisix.apache.org/v2\"")
+	cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ApisixConsumerVersion, "apisix-consumer-version", config.ApisixV2beta3, "the supported ApisixConsumer api group version, can be \"apisix.apache.org/v2beta3\" or \"apisix.apache.org/v2\"")
 	cmd.PersistentFlags().BoolVar(&cfg.Kubernetes.WatchEndpointSlices, "watch-endpointslices", false, "whether to watch endpointslices rather than endpoints")
 	cmd.PersistentFlags().BoolVar(&cfg.Kubernetes.EnableGatewayAPI, "enable-gateway-api", false, "whether to enable support for Gateway API")
 	cmd.PersistentFlags().StringVar(&cfg.APISIX.DefaultClusterBaseURL, "default-apisix-cluster-base-url", "", "the base URL of admin api / manager api for the default APISIX cluster")
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 15b1d10a..2641ef5d 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -96,6 +96,7 @@ type KubernetesConfig struct {
 	IngressVersion             string             `json:"ingress_version" yaml:"ingress_version"`
 	WatchEndpointSlices        bool               `json:"watch_endpoint_slices" yaml:"watch_endpoint_slices"`
 	ApisixRouteVersion         string             `json:"apisix_route_version" yaml:"apisix_route_version"`
+	ApisixConsumerVersion      string             `json:"apisix_consumer_version" yaml:"apisix_consumer_version"`
 	ApisixTlsVersion           string             `json:"apisix_tls_version" yaml:"apisix_tls_version"`
 	ApisixClusterConfigVersion string             `json:"apisix_cluster_config_version" yaml:"apisix_cluster_config_version"`
 	EnableGatewayAPI           bool               `json:"enable_gateway_api" yaml:"enable_gateway_api"`
@@ -133,6 +134,7 @@ func NewDefaultConfig() *Config {
 			IngressClass:               IngressClass,
 			IngressVersion:             IngressNetworkingV1,
 			ApisixRouteVersion:         ApisixRouteV2beta3,
+			ApisixConsumerVersion:      ApisixV2beta3,
 			ApisixTlsVersion:           ApisixV2beta3,
 			ApisixClusterConfigVersion: ApisixV2beta3,
 			WatchEndpointSlices:        false,
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 515d8e6a..311afd50 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -45,6 +45,7 @@ func TestNewConfigFromFile(t *testing.T) {
 			IngressClass:               IngressClass,
 			IngressVersion:             IngressNetworkingV1,
 			ApisixRouteVersion:         ApisixRouteV2beta3,
+			ApisixConsumerVersion:      ApisixV2beta3,
 			ApisixTlsVersion:           ApisixV2beta3,
 			ApisixClusterConfigVersion: ApisixV2beta3,
 		},
@@ -128,6 +129,7 @@ func TestConfigWithEnvVar(t *testing.T) {
 			IngressClass:               IngressClass,
 			IngressVersion:             IngressNetworkingV1,
 			ApisixRouteVersion:         ApisixRouteV2beta3,
+			ApisixConsumerVersion:      ApisixV2beta3,
 			ApisixTlsVersion:           ApisixV2beta3,
 			ApisixClusterConfigVersion: ApisixV2beta3,
 		},
diff --git a/pkg/ingress/apisix_consumer.go b/pkg/ingress/apisix_consumer.go
index edc9b78e..8a456a70 100644
--- a/pkg/ingress/apisix_consumer.go
+++ b/pkg/ingress/apisix_consumer.go
@@ -16,6 +16,7 @@ package ingress
 
 import (
 	"context"
+	"fmt"
 	"time"
 
 	"go.uber.org/zap"
@@ -25,7 +26,8 @@ import (
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/client-go/util/workqueue"
 
-	configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
+	"github.com/apache/apisix-ingress-controller/pkg/config"
+	"github.com/apache/apisix-ingress-controller/pkg/kube"
 	"github.com/apache/apisix-ingress-controller/pkg/log"
 	"github.com/apache/apisix-ingress-controller/pkg/types"
 )
@@ -79,62 +81,113 @@ func (c *apisixConsumerController) runWorker(ctx context.Context) {
 }
 
 func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) error {
-	key := ev.Object.(string)
+	event := ev.Object.(kube.ApisixConsumerEvent)
+	key := event.Key
 	namespace, name, err := cache.SplitMetaNamespaceKey(key)
 	if err != nil {
 		log.Errorf("found ApisixConsumer resource with invalid meta namespace key %s: %s", key, err)
 		return err
 	}
 
-	ac, err := c.controller.apisixConsumerLister.ApisixConsumers(namespace).Get(name)
+	var multiVersioned kube.ApisixConsumer
+	switch event.GroupVersion {
+	case config.ApisixV2beta3:
+		multiVersioned, err = c.controller.apisixConsumerLister.V2beta3(namespace, name)
+	case config.ApisixV2:
+		multiVersioned, err = c.controller.apisixConsumerLister.V2(namespace, name)
+	default:
+		return fmt.Errorf("unsupported ApisixConsumer group version %s", event.GroupVersion)
+	}
+
 	if err != nil {
 		if !k8serrors.IsNotFound(err) {
-			log.Errorf("failed to get ApisixConsumer %s: %s", key, err)
+			log.Errorw("failed to get ApisixConsumer",
+				zap.Error(err),
+				zap.String("key", key),
+				zap.String("version", event.GroupVersion),
+			)
 			return err
 		}
 		if ev.Type != types.EventDelete {
-			log.Warnf("ApisixConsumer %s was deleted before it can be delivered", key)
+			log.Warnw("ApisixConsumer was deleted before it can be delivered",
+				zap.String("key", key),
+				zap.String("version", event.GroupVersion),
+			)
 			// Don't need to retry.
 			return nil
 		}
 	}
 	if ev.Type == types.EventDelete {
-		if ac != nil {
+		if multiVersioned != 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.Warnf("discard the stale ApisixConsumer delete event since the %s exists", key)
 			return nil
 		}
-		ac = ev.Tombstone.(*configv2beta3.ApisixConsumer)
+		multiVersioned = ev.Tombstone.(kube.ApisixConsumer)
 	}
 
-	consumer, err := c.controller.translator.TranslateApisixConsumer(ac)
-	if err != nil {
-		log.Errorw("failed to translate ApisixConsumer",
-			zap.Error(err),
+	switch event.GroupVersion {
+	case config.ApisixV2beta3:
+		ac := multiVersioned.V2beta3()
+
+		consumer, err := c.controller.translator.TranslateApisixConsumerV2beta3(ac)
+		if err != nil {
+			log.Errorw("failed to translate ApisixConsumer",
+				zap.Error(err),
+				zap.Any("ApisixConsumer", ac),
+			)
+			c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err)
+			c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
+			return err
+		}
+		log.Debugw("got consumer object from ApisixConsumer",
+			zap.Any("consumer", consumer),
 			zap.Any("ApisixConsumer", ac),
 		)
-		c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err)
-		c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
-		return err
-	}
-	log.Debug("got consumer object from ApisixConsumer",
-		zap.Any("consumer", consumer),
-		zap.Any("ApisixConsumer", ac),
-	)
 
-	if err := c.controller.syncConsumer(ctx, consumer, ev.Type); err != nil {
-		log.Errorw("failed to sync Consumer to APISIX",
-			zap.Error(err),
+		if err := c.controller.syncConsumer(ctx, consumer, ev.Type); err != nil {
+			log.Errorw("failed to sync Consumer to APISIX",
+				zap.Error(err),
+				zap.Any("consumer", consumer),
+			)
+			c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err)
+			c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
+			return err
+		}
+
+		c.controller.recorderEvent(ac, corev1.EventTypeNormal, _resourceSynced, nil)
+	case config.ApisixV2:
+		ac := multiVersioned.V2()
+
+		consumer, err := c.controller.translator.TranslateApisixConsumerV2(ac)
+		if err != nil {
+			log.Errorw("failed to translate ApisixConsumer",
+				zap.Error(err),
+				zap.Any("ApisixConsumer", ac),
+			)
+			c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err)
+			c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
+			return err
+		}
+		log.Debugw("got consumer object from ApisixConsumer",
 			zap.Any("consumer", consumer),
+			zap.Any("ApisixConsumer", ac),
 		)
-		c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err)
-		c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
-		return err
-	}
 
-	c.controller.recorderEvent(ac, corev1.EventTypeNormal, _resourceSynced, nil)
+		if err := c.controller.syncConsumer(ctx, consumer, ev.Type); err != nil {
+			log.Errorw("failed to sync Consumer to APISIX",
+				zap.Error(err),
+				zap.Any("consumer", consumer),
+			)
+			c.controller.recorderEvent(ac, corev1.EventTypeWarning, _resourceSyncAborted, err)
+			c.controller.recordStatus(ac, _resourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
+			return err
+		}
+
+		c.controller.recorderEvent(ac, corev1.EventTypeNormal, _resourceSynced, nil)
+	}
 	return nil
 }
 
@@ -162,6 +215,11 @@ func (c *apisixConsumerController) handleSyncErr(obj interface{}, err error) {
 }
 
 func (c *apisixConsumerController) onAdd(obj interface{}) {
+	ac, err := kube.NewApisixConsumer(obj)
+	if err != nil {
+		log.Errorw("found ApisixConsumer resource with bad type", zap.Error(err))
+		return
+	}
 	key, err := cache.MetaNamespaceKeyFunc(obj)
 	if err != nil {
 		log.Errorf("found ApisixConsumer resource with bad meta namespace key: %s", err)
@@ -175,17 +233,28 @@ func (c *apisixConsumerController) onAdd(obj interface{}) {
 	)
 
 	c.workqueue.Add(&types.Event{
-		Type:   types.EventAdd,
-		Object: key,
+		Type: types.EventAdd,
+		Object: kube.ApisixConsumerEvent{
+			Key:          key,
+			GroupVersion: ac.GroupVersion(),
+		},
 	})
 
 	c.controller.MetricsCollector.IncrEvents("consumer", "add")
 }
 
 func (c *apisixConsumerController) onUpdate(oldObj, newObj interface{}) {
-	prev := oldObj.(*configv2beta3.ApisixConsumer)
-	curr := newObj.(*configv2beta3.ApisixConsumer)
-	if prev.ResourceVersion >= curr.ResourceVersion {
+	prev, err := kube.NewApisixConsumer(oldObj)
+	if err != nil {
+		log.Errorw("found ApisixConsumer resource with bad type", zap.Error(err))
+		return
+	}
+	curr, err := kube.NewApisixConsumer(newObj)
+	if err != nil {
+		log.Errorw("found ApisixConsumer resource with bad type", zap.Error(err))
+		return
+	}
+	if prev.ResourceVersion() >= curr.ResourceVersion() {
 		return
 	}
 	key, err := cache.MetaNamespaceKeyFunc(newObj)
@@ -202,21 +271,29 @@ func (c *apisixConsumerController) onUpdate(oldObj, newObj interface{}) {
 	)
 
 	c.workqueue.Add(&types.Event{
-		Type:   types.EventUpdate,
-		Object: key,
+		Type: types.EventUpdate,
+		Object: kube.ApisixConsumerEvent{
+			Key:          key,
+			OldObject:    prev,
+			GroupVersion: curr.GroupVersion(),
+		},
 	})
 
 	c.controller.MetricsCollector.IncrEvents("consumer", "update")
 }
 
 func (c *apisixConsumerController) onDelete(obj interface{}) {
-	ac, ok := obj.(*configv2beta3.ApisixConsumer)
-	if !ok {
+	ac, err := kube.NewApisixConsumer(obj)
+	if err != nil {
 		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
 		if !ok {
 			return
 		}
-		ac = tombstone.Obj.(*configv2beta3.ApisixConsumer)
+		ac, err = kube.NewApisixConsumer(tombstone.Obj)
+		if err != nil {
+			log.Errorw("found ApisixConsumer resource with bad type", zap.Error(err))
+			return
+		}
 	}
 
 	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
@@ -231,8 +308,11 @@ func (c *apisixConsumerController) onDelete(obj interface{}) {
 		zap.Any("final state", ac),
 	)
 	c.workqueue.Add(&types.Event{
-		Type:      types.EventDelete,
-		Object:    key,
+		Type: types.EventDelete,
+		Object: kube.ApisixConsumerEvent{
+			Key:          key,
+			GroupVersion: ac.GroupVersion(),
+		},
 		Tombstone: ac,
 	})
 
diff --git a/pkg/ingress/compare.go b/pkg/ingress/compare.go
index 6d2f560d..6ab081e4 100644
--- a/pkg/ingress/compare.go
+++ b/pkg/ingress/compare.go
@@ -130,7 +130,7 @@ func (c *Controller) CompareResources(ctx context.Context) error {
 				ctx.Done()
 			} else {
 				for _, con := range retConsumer.Items {
-					consumer, err := c.translator.TranslateApisixConsumer(&con)
+					consumer, err := c.translator.TranslateApisixConsumerV2beta3(&con)
 					if err != nil {
 						log.Error(err.Error())
 						ctx.Done()
diff --git a/pkg/ingress/controller.go b/pkg/ingress/controller.go
index c1afded2..33c273c8 100644
--- a/pkg/ingress/controller.go
+++ b/pkg/ingress/controller.go
@@ -114,7 +114,7 @@ type Controller struct {
 	apisixClusterConfigLister   kube.ApisixClusterConfigLister
 	apisixClusterConfigInformer cache.SharedIndexInformer
 	apisixConsumerInformer      cache.SharedIndexInformer
-	apisixConsumerLister        listersv2beta3.ApisixConsumerLister
+	apisixConsumerLister        kube.ApisixConsumerLister
 	apisixPluginConfigInformer  cache.SharedIndexInformer
 	apisixPluginConfigLister    kube.ApisixPluginConfigLister
 	gatewayInformer             cache.SharedIndexInformer
@@ -204,6 +204,7 @@ func (c *Controller) initWhenStartLeading() {
 		apisixRouteInformer         cache.SharedIndexInformer
 		apisixTlsInformer           cache.SharedIndexInformer
 		apisixClusterConfigInformer cache.SharedIndexInformer
+		apisixConsumerInformer      cache.SharedIndexInformer
 	)
 
 	kubeFactory := c.kubeClient.NewSharedIndexInformerFactory()
@@ -234,7 +235,10 @@ func (c *Controller) initWhenStartLeading() {
 		apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Lister(),
 		apisixFactory.Apisix().V2().ApisixClusterConfigs().Lister(),
 	)
-	c.apisixConsumerLister = apisixFactory.Apisix().V2beta3().ApisixConsumers().Lister()
+	c.apisixConsumerLister = kube.NewApisixConsumerLister(
+		apisixFactory.Apisix().V2beta3().ApisixConsumers().Lister(),
+		apisixFactory.Apisix().V2().ApisixConsumers().Lister(),
+	)
 	c.apisixPluginConfigLister = kube.NewApisixPluginConfigLister(
 		apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Lister(),
 	)
@@ -289,6 +293,13 @@ func (c *Controller) initWhenStartLeading() {
 		panic(fmt.Errorf("unsupported ApisixClusterConfig version %v", c.cfg.Kubernetes.ApisixClusterConfigVersion))
 	}
 
+	switch c.cfg.Kubernetes.ApisixConsumerVersion {
+	case config.ApisixRouteV2beta3:
+		apisixConsumerInformer = apisixFactory.Apisix().V2beta3().ApisixConsumers().Informer()
+	case config.ApisixRouteV2:
+		apisixConsumerInformer = apisixFactory.Apisix().V2().ApisixConsumers().Informer()
+	}
+
 	c.namespaceInformer = kubeFactory.Core().V1().Namespaces().Informer()
 	c.podInformer = kubeFactory.Core().V1().Pods().Informer()
 	c.svcInformer = kubeFactory.Core().V1().Services().Informer()
@@ -298,7 +309,7 @@ func (c *Controller) initWhenStartLeading() {
 	c.apisixClusterConfigInformer = apisixClusterConfigInformer
 	c.secretInformer = kubeFactory.Core().V1().Secrets().Informer()
 	c.apisixTlsInformer = apisixTlsInformer
-	c.apisixConsumerInformer = apisixFactory.Apisix().V2beta3().ApisixConsumers().Informer()
+	c.apisixConsumerInformer = apisixConsumerInformer
 	c.apisixPluginConfigInformer = apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Informer()
 
 	if c.cfg.Kubernetes.WatchEndpointSlices {
diff --git a/pkg/ingress/status.go b/pkg/ingress/status.go
index c2d090ed..604227a0 100644
--- a/pkg/ingress/status.go
+++ b/pkg/ingress/status.go
@@ -177,6 +177,23 @@ func (c *Controller) recordStatus(at interface{}, reason string, err error, stat
 				)
 			}
 		}
+	case *configv2.ApisixConsumer:
+		// set to status
+		if v.Status.Conditions == nil {
+			conditions := make([]metav1.Condition, 0)
+			v.Status.Conditions = conditions
+		}
+		if c.verifyGeneration(&v.Status.Conditions, condition) {
+			meta.SetStatusCondition(&v.Status.Conditions, condition)
+			if _, errRecord := client.ApisixV2().ApisixConsumers(v.Namespace).
+				UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+				log.Errorw("failed to record status change for ApisixConsumer",
+					zap.Error(errRecord),
+					zap.String("name", v.Name),
+					zap.String("namespace", v.Namespace),
+				)
+			}
+		}
 	case *configv2beta3.ApisixPluginConfig:
 		// set to status
 		if v.Status.Conditions == nil {
diff --git a/pkg/kube/apisix_consumer.go b/pkg/kube/apisix_consumer.go
new file mode 100644
index 00000000..a9d188d9
--- /dev/null
+++ b/pkg/kube/apisix_consumer.go
@@ -0,0 +1,169 @@
+// 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"
+
+	"github.com/apache/apisix-ingress-controller/pkg/config"
+	configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+	configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
+	listersv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2"
+	listersv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2beta3"
+)
+
+// ApisixConsumerLister is an encapsulation for the lister of ApisixConsumer,
+// it aims at to be compatible with different ApisixConsumer versions.
+type ApisixConsumerLister interface {
+	// V2beta3 gets the ApisixConsumer in apisix.apache.org/v2beta3.
+	V2beta3(string, string) (ApisixConsumer, error)
+	// V2 gets the ApisixConsumer in apisix.apache.org/v2.
+	V2(string, string) (ApisixConsumer, error)
+}
+
+// ApisixConsumerInformer is an encapsulation for the informer of ApisixConsumer,
+// it aims at to be compatible with different ApisixConsumer versions.
+type ApisixConsumerInformer interface {
+	Run(chan struct{})
+}
+
+// ApisixConsumer is an encapsulation for ApisixConsumer resource with different
+// versions, for now, they are apisix.apache.org/v2beta3 and apisix.apache.org/v2
+type ApisixConsumer interface {
+	// GroupVersion returns the api group version of the
+	// real ApisixConsumer.
+	GroupVersion() string
+	// V2beta3 returns the ApisixConsumer in apisix.apache.org/v2beta3, the real
+	// ApisixConsumer must be in this group version, otherwise will panic.
+	V2beta3() *configv2beta3.ApisixConsumer
+	// V2 returns the ApisixConsumer in apisix.apache.org/v2, the real
+	// ApisixConsumer must be in this group version, otherwise will panic.
+	V2() *configv2.ApisixConsumer
+	// ResourceVersion returns the the resource version field inside
+	// the real ApisixConsumer.
+	ResourceVersion() string
+}
+
+// ApisixConsumerEvent contains the ApisixConsumer key (namespace/name)
+// and the group version message.
+type ApisixConsumerEvent struct {
+	Key          string
+	OldObject    ApisixConsumer
+	GroupVersion string
+}
+
+type apisixConsumer struct {
+	groupVersion string
+	v2beta3      *configv2beta3.ApisixConsumer
+	v2           *configv2.ApisixConsumer
+}
+
+func (ac *apisixConsumer) V2beta3() *configv2beta3.ApisixConsumer {
+	if ac.groupVersion != config.ApisixV2beta3 {
+		panic("not a apisix.apache.org/v2beta3 Consumer")
+	}
+	return ac.v2beta3
+}
+
+func (ac *apisixConsumer) V2() *configv2.ApisixConsumer {
+	if ac.groupVersion != config.ApisixV2 {
+		panic("not a apisix.apache.org/v2 Consumer")
+	}
+	return ac.v2
+}
+
+func (ac *apisixConsumer) GroupVersion() string {
+	return ac.groupVersion
+}
+
+func (ac *apisixConsumer) ResourceVersion() string {
+	if ac.groupVersion == config.ApisixV2beta3 {
+		return ac.V2beta3().ResourceVersion
+	}
+	return ac.V2().ResourceVersion
+}
+
+type apisixConsumerLister struct {
+	v2beta3Lister listersv2beta3.ApisixConsumerLister
+	v2Lister      listersv2.ApisixConsumerLister
+}
+
+func (l *apisixConsumerLister) V2beta3(namespace, name string) (ApisixConsumer, error) {
+	ac, err := l.v2beta3Lister.ApisixConsumers(namespace).Get(name)
+	if err != nil {
+		return nil, err
+	}
+	return &apisixConsumer{
+		groupVersion: config.ApisixV2beta3,
+		v2beta3:      ac,
+	}, nil
+}
+
+func (l *apisixConsumerLister) V2(namespace, name string) (ApisixConsumer, error) {
+	ac, err := l.v2Lister.ApisixConsumers(namespace).Get(name)
+	if err != nil {
+		return nil, err
+	}
+	return &apisixConsumer{
+		groupVersion: config.ApisixV2,
+		v2:           ac,
+	}, nil
+}
+
+// MustNewApisixConsumer creates a kube.ApisixConsumer object according to the
+// type of obj.
+func MustNewApisixConsumer(obj interface{}) ApisixConsumer {
+	switch ac := obj.(type) {
+	case *configv2beta3.ApisixConsumer:
+		return &apisixConsumer{
+			groupVersion: config.ApisixV2beta3,
+			v2beta3:      ac,
+		}
+	case *configv2.ApisixConsumer:
+		return &apisixConsumer{
+			groupVersion: config.ApisixV2,
+			v2:           ac,
+		}
+	default:
+		panic("invalid ApisixConsumer type")
+	}
+}
+
+// NewApisixConsumer creates a kube.ApisixConsumer object according to the
+// type of obj. It returns nil and the error reason when the
+// type assertion fails.
+func NewApisixConsumer(obj interface{}) (ApisixConsumer, error) {
+	switch ac := obj.(type) {
+	case *configv2beta3.ApisixConsumer:
+		return &apisixConsumer{
+			groupVersion: config.ApisixV2beta3,
+			v2beta3:      ac,
+		}, nil
+	case *configv2.ApisixConsumer:
+		return &apisixConsumer{
+			groupVersion: config.ApisixV2,
+			v2:           ac,
+		}, nil
+	default:
+		return nil, errors.New("invalid ApisixConsumer type")
+	}
+}
+
+func NewApisixConsumerLister(v2beta3 listersv2beta3.ApisixConsumerLister, v2 listersv2.ApisixConsumerLister) ApisixConsumerLister {
+	return &apisixConsumerLister{
+		v2beta3Lister: v2beta3,
+		v2Lister:      v2,
+	}
+}
diff --git a/pkg/kube/translation/apisix_consumer.go b/pkg/kube/translation/apisix_consumer.go
index 04525799..982b741f 100644
--- a/pkg/kube/translation/apisix_consumer.go
+++ b/pkg/kube/translation/apisix_consumer.go
@@ -17,35 +17,73 @@ package translation
 import (
 	"fmt"
 
+	configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
 	configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
 	apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
-func (t *translator) TranslateApisixConsumer(ac *configv2beta3.ApisixConsumer) (*apisixv1.Consumer, error) {
+func (t *translator) TranslateApisixConsumerV2beta3(ac *configv2beta3.ApisixConsumer) (*apisixv1.Consumer, error) {
 	// As the CRD schema ensures that only one authN can be configured,
 	// so here the order is no matter.
 
 	plugins := make(apisixv1.Plugins)
 	if ac.Spec.AuthParameter.KeyAuth != nil {
-		cfg, err := t.translateConsumerKeyAuthPlugin(ac.Namespace, ac.Spec.AuthParameter.KeyAuth)
+		cfg, err := t.translateConsumerKeyAuthPluginV2beta3(ac.Namespace, ac.Spec.AuthParameter.KeyAuth)
 		if err != nil {
 			return nil, fmt.Errorf("invalid key auth config: %s", err)
 		}
 		plugins["key-auth"] = cfg
 	} else if ac.Spec.AuthParameter.BasicAuth != nil {
-		cfg, err := t.translateConsumerBasicAuthPlugin(ac.Namespace, ac.Spec.AuthParameter.BasicAuth)
+		cfg, err := t.translateConsumerBasicAuthPluginV2beta3(ac.Namespace, ac.Spec.AuthParameter.BasicAuth)
 		if err != nil {
 			return nil, fmt.Errorf("invalid basic auth config: %s", err)
 		}
 		plugins["basic-auth"] = cfg
 	} else if ac.Spec.AuthParameter.JwtAuth != nil {
-		cfg, err := t.translateConsumerJwtAuthPlugin(ac.Namespace, ac.Spec.AuthParameter.JwtAuth)
+		cfg, err := t.translateConsumerJwtAuthPluginV2beta3(ac.Namespace, ac.Spec.AuthParameter.JwtAuth)
 		if err != nil {
 			return nil, fmt.Errorf("invalid jwt auth config: %s", err)
 		}
 		plugins["jwt-auth"] = cfg
 	} else if ac.Spec.AuthParameter.WolfRBAC != nil {
-		cfg, err := t.translateConsumerWolfRBACPlugin(ac.Namespace, ac.Spec.AuthParameter.WolfRBAC)
+		cfg, err := t.translateConsumerWolfRBACPluginV2beta3(ac.Namespace, ac.Spec.AuthParameter.WolfRBAC)
+		if err != nil {
+			return nil, fmt.Errorf("invalid wolf rbac config: %s", err)
+		}
+		plugins["wolf-rbac"] = cfg
+	}
+
+	consumer := apisixv1.NewDefaultConsumer()
+	consumer.Username = apisixv1.ComposeConsumerName(ac.Namespace, ac.Name)
+	consumer.Plugins = plugins
+	return consumer, nil
+}
+
+func (t *translator) TranslateApisixConsumerV2(ac *configv2.ApisixConsumer) (*apisixv1.Consumer, error) {
+	// As the CRD schema ensures that only one authN can be configured,
+	// so here the order is no matter.
+
+	plugins := make(apisixv1.Plugins)
+	if ac.Spec.AuthParameter.KeyAuth != nil {
+		cfg, err := t.translateConsumerKeyAuthPluginV2(ac.Namespace, ac.Spec.AuthParameter.KeyAuth)
+		if err != nil {
+			return nil, fmt.Errorf("invalid key auth config: %s", err)
+		}
+		plugins["key-auth"] = cfg
+	} else if ac.Spec.AuthParameter.BasicAuth != nil {
+		cfg, err := t.translateConsumerBasicAuthPluginV2(ac.Namespace, ac.Spec.AuthParameter.BasicAuth)
+		if err != nil {
+			return nil, fmt.Errorf("invalid basic auth config: %s", err)
+		}
+		plugins["basic-auth"] = cfg
+	} else if ac.Spec.AuthParameter.JwtAuth != nil {
+		cfg, err := t.translateConsumerJwtAuthPluginV2(ac.Namespace, ac.Spec.AuthParameter.JwtAuth)
+		if err != nil {
+			return nil, fmt.Errorf("invalid jwt auth config: %s", err)
+		}
+		plugins["jwt-auth"] = cfg
+	} else if ac.Spec.AuthParameter.WolfRBAC != nil {
+		cfg, err := t.translateConsumerWolfRBACPluginV2(ac.Namespace, ac.Spec.AuthParameter.WolfRBAC)
 		if err != nil {
 			return nil, fmt.Errorf("invalid wolf rbac config: %s", err)
 		}
diff --git a/pkg/kube/translation/apisix_consumer_test.go b/pkg/kube/translation/apisix_consumer_test.go
index 775e2a3a..a875c8a6 100644
--- a/pkg/kube/translation/apisix_consumer_test.go
+++ b/pkg/kube/translation/apisix_consumer_test.go
@@ -20,11 +20,12 @@ import (
 	"github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
+	configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
 	configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
 	apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
-func TestTranslateApisixConsumer(t *testing.T) {
+func TestTranslateApisixConsumerV2beta3(t *testing.T) {
 	ac := &configv2beta3.ApisixConsumer{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "jack",
@@ -41,7 +42,7 @@ func TestTranslateApisixConsumer(t *testing.T) {
 			},
 		},
 	}
-	consumer, err := (&translator{}).TranslateApisixConsumer(ac)
+	consumer, err := (&translator{}).TranslateApisixConsumerV2beta3(ac)
 	assert.Nil(t, err)
 	assert.Len(t, consumer.Plugins, 1)
 	cfg := consumer.Plugins["basic-auth"].(*apisixv1.BasicAuthConsumerConfig)
@@ -63,7 +64,7 @@ func TestTranslateApisixConsumer(t *testing.T) {
 			},
 		},
 	}
-	consumer, err = (&translator{}).TranslateApisixConsumer(ac)
+	consumer, err = (&translator{}).TranslateApisixConsumerV2beta3(ac)
 	assert.Nil(t, err)
 	assert.Len(t, consumer.Plugins, 1)
 	cfg2 := consumer.Plugins["key-auth"].(*apisixv1.KeyAuthConsumerConfig)
@@ -90,7 +91,7 @@ func TestTranslateApisixConsumer(t *testing.T) {
 			},
 		},
 	}
-	consumer, err = (&translator{}).TranslateApisixConsumer(ac)
+	consumer, err = (&translator{}).TranslateApisixConsumerV2beta3(ac)
 	assert.Nil(t, err)
 	assert.Len(t, consumer.Plugins, 1)
 	cfg3 := consumer.Plugins["jwt-auth"].(*apisixv1.JwtAuthConsumerConfig)
@@ -118,7 +119,112 @@ func TestTranslateApisixConsumer(t *testing.T) {
 			},
 		},
 	}
-	consumer, err = (&translator{}).TranslateApisixConsumer(ac)
+	consumer, err = (&translator{}).TranslateApisixConsumerV2beta3(ac)
+	assert.Nil(t, err)
+	assert.Len(t, consumer.Plugins, 1)
+	cfg4 := consumer.Plugins["wolf-rbac"].(*apisixv1.WolfRBACConsumerConfig)
+	assert.Equal(t, "https://httpbin.org", cfg4.Server)
+	assert.Equal(t, "test01", cfg4.Appid)
+
+	// No test test cases for secret references as we already test them
+	// in plugin_test.go.
+}
+
+func TestTranslateApisixConsumerV2(t *testing.T) {
+	ac := &configv2.ApisixConsumer{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "jack",
+			Namespace: "qa",
+		},
+		Spec: configv2.ApisixConsumerSpec{
+			AuthParameter: configv2.ApisixConsumerAuthParameter{
+				BasicAuth: &configv2.ApisixConsumerBasicAuth{
+					Value: &configv2.ApisixConsumerBasicAuthValue{
+						Username: "jack",
+						Password: "jacknice",
+					},
+				},
+			},
+		},
+	}
+	consumer, err := (&translator{}).TranslateApisixConsumerV2(ac)
+	assert.Nil(t, err)
+	assert.Len(t, consumer.Plugins, 1)
+	cfg := consumer.Plugins["basic-auth"].(*apisixv1.BasicAuthConsumerConfig)
+	assert.Equal(t, "jack", cfg.Username)
+	assert.Equal(t, "jacknice", cfg.Password)
+
+	ac = &configv2.ApisixConsumer{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "jack",
+			Namespace: "qa",
+		},
+		Spec: configv2.ApisixConsumerSpec{
+			AuthParameter: configv2.ApisixConsumerAuthParameter{
+				KeyAuth: &configv2.ApisixConsumerKeyAuth{
+					Value: &configv2.ApisixConsumerKeyAuthValue{
+						Key: "qwerty",
+					},
+				},
+			},
+		},
+	}
+	consumer, err = (&translator{}).TranslateApisixConsumerV2(ac)
+	assert.Nil(t, err)
+	assert.Len(t, consumer.Plugins, 1)
+	cfg2 := consumer.Plugins["key-auth"].(*apisixv1.KeyAuthConsumerConfig)
+	assert.Equal(t, "qwerty", cfg2.Key)
+
+	ac = &configv2.ApisixConsumer{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "jack",
+			Namespace: "qa",
+		},
+		Spec: configv2.ApisixConsumerSpec{
+			AuthParameter: configv2.ApisixConsumerAuthParameter{
+				JwtAuth: &configv2.ApisixConsumerJwtAuth{
+					Value: &configv2.ApisixConsumerJwtAuthValue{
+						Key:          "foo",
+						Secret:       "123",
+						PublicKey:    "public",
+						PrivateKey:   "private",
+						Algorithm:    "HS256",
+						Exp:          int64(1000),
+						Base64Secret: true,
+					},
+				},
+			},
+		},
+	}
+	consumer, err = (&translator{}).TranslateApisixConsumerV2(ac)
+	assert.Nil(t, err)
+	assert.Len(t, consumer.Plugins, 1)
+	cfg3 := consumer.Plugins["jwt-auth"].(*apisixv1.JwtAuthConsumerConfig)
+	assert.Equal(t, "foo", cfg3.Key)
+	assert.Equal(t, "123", cfg3.Secret)
+	assert.Equal(t, "public", cfg3.PublicKey)
+	assert.Equal(t, "private", cfg3.PrivateKey)
+	assert.Equal(t, "HS256", cfg3.Algorithm)
+	assert.Equal(t, int64(1000), cfg3.Exp)
+	assert.Equal(t, true, cfg3.Base64Secret)
+
+	ac = &configv2.ApisixConsumer{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "jack",
+			Namespace: "qa",
+		},
+		Spec: configv2.ApisixConsumerSpec{
+			AuthParameter: configv2.ApisixConsumerAuthParameter{
+				WolfRBAC: &configv2.ApisixConsumerWolfRBAC{
+					Value: &configv2.ApisixConsumerWolfRBACValue{
+						Server: "https://httpbin.org",
+						Appid:  "test01",
+					},
+				},
+			},
+		},
+	}
+	consumer, err = (&translator{}).TranslateApisixConsumerV2(ac)
 	assert.Nil(t, err)
 	assert.Len(t, consumer.Plugins, 1)
 	cfg4 := consumer.Plugins["wolf-rbac"].(*apisixv1.WolfRBACConsumerConfig)
diff --git a/pkg/kube/translation/plugin.go b/pkg/kube/translation/plugin.go
index c2a9b109..5b532932 100644
--- a/pkg/kube/translation/plugin.go
+++ b/pkg/kube/translation/plugin.go
@@ -73,7 +73,7 @@ func (t *translator) translateTrafficSplitPlugin(ctx *TranslateContext, ns strin
 	return tsCfg, nil
 }
 
-func (t *translator) translateConsumerKeyAuthPlugin(consumerNamespace string, cfg *configv2beta3.ApisixConsumerKeyAuth) (*apisixv1.KeyAuthConsumerConfig, error) {
+func (t *translator) translateConsumerKeyAuthPluginV2beta3(consumerNamespace string, cfg *configv2beta3.ApisixConsumerKeyAuth) (*apisixv1.KeyAuthConsumerConfig, error) {
 	if cfg.Value != nil {
 		return &apisixv1.KeyAuthConsumerConfig{Key: cfg.Value.Key}, nil
 	}
@@ -89,7 +89,7 @@ func (t *translator) translateConsumerKeyAuthPlugin(consumerNamespace string, cf
 	return &apisixv1.KeyAuthConsumerConfig{Key: string(raw)}, nil
 }
 
-func (t *translator) translateConsumerBasicAuthPlugin(consumerNamespace string, cfg *configv2beta3.ApisixConsumerBasicAuth) (*apisixv1.BasicAuthConsumerConfig, error) {
+func (t *translator) translateConsumerBasicAuthPluginV2beta3(consumerNamespace string, cfg *configv2beta3.ApisixConsumerBasicAuth) (*apisixv1.BasicAuthConsumerConfig, error) {
 	if cfg.Value != nil {
 		return &apisixv1.BasicAuthConsumerConfig{
 			Username: cfg.Value.Username,
@@ -115,7 +115,49 @@ func (t *translator) translateConsumerBasicAuthPlugin(consumerNamespace string,
 	}, nil
 }
 
-func (t *translator) translateConsumerWolfRBACPlugin(consumerNamespace string, cfg *configv2beta3.ApisixConsumerWolfRBAC) (*apisixv1.WolfRBACConsumerConfig, error) {
+func (t *translator) translateConsumerKeyAuthPluginV2(consumerNamespace string, cfg *configv2.ApisixConsumerKeyAuth) (*apisixv1.KeyAuthConsumerConfig, error) {
+	if cfg.Value != nil {
+		return &apisixv1.KeyAuthConsumerConfig{Key: cfg.Value.Key}, nil
+	}
+
+	sec, err := t.SecretLister.Secrets(consumerNamespace).Get(cfg.SecretRef.Name)
+	if err != nil {
+		return nil, err
+	}
+	raw, ok := sec.Data["key"]
+	if !ok || len(raw) == 0 {
+		return nil, _errKeyNotFoundOrInvalid
+	}
+	return &apisixv1.KeyAuthConsumerConfig{Key: string(raw)}, nil
+}
+
+func (t *translator) translateConsumerBasicAuthPluginV2(consumerNamespace string, cfg *configv2.ApisixConsumerBasicAuth) (*apisixv1.BasicAuthConsumerConfig, error) {
+	if cfg.Value != nil {
+		return &apisixv1.BasicAuthConsumerConfig{
+			Username: cfg.Value.Username,
+			Password: cfg.Value.Password,
+		}, nil
+	}
+
+	sec, err := t.SecretLister.Secrets(consumerNamespace).Get(cfg.SecretRef.Name)
+	if err != nil {
+		return nil, err
+	}
+	raw1, ok := sec.Data["username"]
+	if !ok || len(raw1) == 0 {
+		return nil, _errUsernameNotFoundOrInvalid
+	}
+	raw2, ok := sec.Data["password"]
+	if !ok || len(raw2) == 0 {
+		return nil, _errPasswordNotFoundOrInvalid
+	}
+	return &apisixv1.BasicAuthConsumerConfig{
+		Username: string(raw1),
+		Password: string(raw2),
+	}, nil
+}
+
+func (t *translator) translateConsumerWolfRBACPluginV2beta3(consumerNamespace string, cfg *configv2beta3.ApisixConsumerWolfRBAC) (*apisixv1.WolfRBACConsumerConfig, error) {
 	if cfg.Value != nil {
 		return &apisixv1.WolfRBACConsumerConfig{
 			Server:       cfg.Value.Server,
@@ -137,7 +179,80 @@ func (t *translator) translateConsumerWolfRBACPlugin(consumerNamespace string, c
 	}, nil
 }
 
-func (t *translator) translateConsumerJwtAuthPlugin(consumerNamespace string, cfg *configv2beta3.ApisixConsumerJwtAuth) (*apisixv1.JwtAuthConsumerConfig, error) {
+func (t *translator) translateConsumerWolfRBACPluginV2(consumerNamespace string, cfg *configv2.ApisixConsumerWolfRBAC) (*apisixv1.WolfRBACConsumerConfig, error) {
+	if cfg.Value != nil {
+		return &apisixv1.WolfRBACConsumerConfig{
+			Server:       cfg.Value.Server,
+			Appid:        cfg.Value.Appid,
+			HeaderPrefix: cfg.Value.HeaderPrefix,
+		}, nil
+	}
+	sec, err := t.SecretLister.Secrets(consumerNamespace).Get(cfg.SecretRef.Name)
+	if err != nil {
+		return nil, err
+	}
+	raw1 := sec.Data["server"]
+	raw2 := sec.Data["appid"]
+	raw3 := sec.Data["header_prefix"]
+	return &apisixv1.WolfRBACConsumerConfig{
+		Server:       string(raw1),
+		Appid:        string(raw2),
+		HeaderPrefix: string(raw3),
+	}, nil
+}
+
+func (t *translator) translateConsumerJwtAuthPluginV2beta3(consumerNamespace string, cfg *configv2beta3.ApisixConsumerJwtAuth) (*apisixv1.JwtAuthConsumerConfig, error) {
+	if cfg.Value != nil {
+		// The field exp must be a positive integer, default value 86400.
+		if cfg.Value.Exp < 1 {
+			cfg.Value.Exp = _jwtAuthExpDefaultValue
+		}
+		return &apisixv1.JwtAuthConsumerConfig{
+			Key:          cfg.Value.Key,
+			Secret:       cfg.Value.Secret,
+			PublicKey:    cfg.Value.PublicKey,
+			PrivateKey:   cfg.Value.PrivateKey,
+			Algorithm:    cfg.Value.Algorithm,
+			Exp:          cfg.Value.Exp,
+			Base64Secret: cfg.Value.Base64Secret,
+		}, nil
+	}
+
+	sec, err := t.SecretLister.Secrets(consumerNamespace).Get(cfg.SecretRef.Name)
+	if err != nil {
+		return nil, err
+	}
+	keyRaw, ok := sec.Data["key"]
+	if !ok || len(keyRaw) == 0 {
+		return nil, _errKeyNotFoundOrInvalid
+	}
+	base64SecretRaw := sec.Data["base64_secret"]
+	var base64Secret bool
+	if string(base64SecretRaw) == "true" {
+		base64Secret = true
+	}
+	expRaw := sec.Data["exp"]
+	exp, _ := strconv.ParseInt(string(expRaw), 10, 64)
+	// The field exp must be a positive integer, default value 86400.
+	if exp < 1 {
+		exp = _jwtAuthExpDefaultValue
+	}
+	secretRaw := sec.Data["secret"]
+	publicKeyRaw := sec.Data["public_key"]
+	privateKeyRaw := sec.Data["private_key"]
+	algorithmRaw := sec.Data["algorithm"]
+	return &apisixv1.JwtAuthConsumerConfig{
+		Key:          string(keyRaw),
+		Secret:       string(secretRaw),
+		PublicKey:    string(publicKeyRaw),
+		PrivateKey:   string(privateKeyRaw),
+		Algorithm:    string(algorithmRaw),
+		Exp:          exp,
+		Base64Secret: base64Secret,
+	}, nil
+}
+
+func (t *translator) translateConsumerJwtAuthPluginV2(consumerNamespace string, cfg *configv2.ApisixConsumerJwtAuth) (*apisixv1.JwtAuthConsumerConfig, error) {
 	if cfg.Value != nil {
 		// The field exp must be a positive integer, default value 86400.
 		if cfg.Value.Exp < 1 {
diff --git a/pkg/kube/translation/plugin_test.go b/pkg/kube/translation/plugin_test.go
index a6cad20f..94cbc9ee 100644
--- a/pkg/kube/translation/plugin_test.go
+++ b/pkg/kube/translation/plugin_test.go
@@ -539,7 +539,7 @@ func TestTranslateConsumerKeyAuthPluginWithInPlaceValue(t *testing.T) {
 	keyAuth := &configv2beta3.ApisixConsumerKeyAuth{
 		Value: &configv2beta3.ApisixConsumerKeyAuthValue{Key: "abc"},
 	}
-	cfg, err := (&translator{}).translateConsumerKeyAuthPlugin("default", keyAuth)
+	cfg, err := (&translator{}).translateConsumerKeyAuthPluginV2beta3("default", keyAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, "abc", cfg.Key)
 }
@@ -582,11 +582,11 @@ func TestTranslateConsumerKeyAuthWithSecretRef(t *testing.T) {
 	keyAuth := &configv2beta3.ApisixConsumerKeyAuth{
 		SecretRef: &corev1.LocalObjectReference{Name: "abc-key-auth"},
 	}
-	cfg, err := tr.translateConsumerKeyAuthPlugin("default", keyAuth)
+	cfg, err := tr.translateConsumerKeyAuthPluginV2beta3("default", keyAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, "abc", cfg.Key)
 
-	cfg, err = tr.translateConsumerKeyAuthPlugin("default2", keyAuth)
+	cfg, err = tr.translateConsumerKeyAuthPluginV2beta3("default2", keyAuth)
 	assert.Nil(t, cfg)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "not found")
@@ -596,7 +596,7 @@ func TestTranslateConsumerKeyAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerKeyAuthPlugin("default", keyAuth)
+	cfg, err = tr.translateConsumerKeyAuthPluginV2beta3("default", keyAuth)
 	assert.Nil(t, cfg)
 	assert.Equal(t, _errKeyNotFoundOrInvalid, err)
 
@@ -611,7 +611,7 @@ func TestTranslateConsumerBasicAuthPluginWithInPlaceValue(t *testing.T) {
 			Password: "jacknice",
 		},
 	}
-	cfg, err := (&translator{}).translateConsumerBasicAuthPlugin("default", basicAuth)
+	cfg, err := (&translator{}).translateConsumerBasicAuthPluginV2beta3("default", basicAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, "jack", cfg.Username)
 	assert.Equal(t, "jacknice", cfg.Password)
@@ -656,12 +656,12 @@ func TestTranslateConsumerBasicAuthWithSecretRef(t *testing.T) {
 	basicAuth := &configv2beta3.ApisixConsumerBasicAuth{
 		SecretRef: &corev1.LocalObjectReference{Name: "jack-basic-auth"},
 	}
-	cfg, err := tr.translateConsumerBasicAuthPlugin("default", basicAuth)
+	cfg, err := tr.translateConsumerBasicAuthPluginV2beta3("default", basicAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, "jack", cfg.Username)
 	assert.Equal(t, "jacknice", cfg.Password)
 
-	cfg, err = tr.translateConsumerBasicAuthPlugin("default2", basicAuth)
+	cfg, err = tr.translateConsumerBasicAuthPluginV2beta3("default2", basicAuth)
 	assert.Nil(t, cfg)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "not found")
@@ -671,7 +671,7 @@ func TestTranslateConsumerBasicAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerBasicAuthPlugin("default", basicAuth)
+	cfg, err = tr.translateConsumerBasicAuthPluginV2beta3("default", basicAuth)
 	assert.Nil(t, cfg)
 	assert.Equal(t, _errPasswordNotFoundOrInvalid, err)
 
@@ -680,7 +680,7 @@ func TestTranslateConsumerBasicAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerBasicAuthPlugin("default", basicAuth)
+	cfg, err = tr.translateConsumerBasicAuthPluginV2beta3("default", basicAuth)
 	assert.Nil(t, cfg)
 	assert.Equal(t, _errUsernameNotFoundOrInvalid, err)
 
@@ -700,7 +700,7 @@ func TestTranslateConsumerJwtAuthPluginWithInPlaceValue(t *testing.T) {
 			Base64Secret: true,
 		},
 	}
-	cfg, err := (&translator{}).translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err := (&translator{}).translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, "foo", cfg.Key)
 	assert.Equal(t, "foo-secret", cfg.Secret)
@@ -711,7 +711,7 @@ func TestTranslateConsumerJwtAuthPluginWithInPlaceValue(t *testing.T) {
 	assert.Equal(t, true, cfg.Base64Secret)
 
 	jwtAuth.Value.Exp = int64(-1)
-	cfg, err = (&translator{}).translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = (&translator{}).translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, int64(_jwtAuthExpDefaultValue), cfg.Exp)
 
@@ -720,7 +720,7 @@ func TestTranslateConsumerJwtAuthPluginWithInPlaceValue(t *testing.T) {
 			Key: "foo2",
 		},
 	}
-	cfg, err = (&translator{}).translateConsumerJwtAuthPlugin("default", jwtAuth2)
+	cfg, err = (&translator{}).translateConsumerJwtAuthPluginV2beta3("default", jwtAuth2)
 	assert.Nil(t, err)
 	assert.Equal(t, "foo2", cfg.Key)
 }
@@ -769,7 +769,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	jwtAuth := &configv2beta3.ApisixConsumerJwtAuth{
 		SecretRef: &corev1.LocalObjectReference{Name: "jack-jwt-auth"},
 	}
-	cfg, err := tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err := tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 	assert.Equal(t, "foo", cfg.Key)
 	assert.Equal(t, "foo-secret", cfg.Secret)
@@ -779,7 +779,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Equal(t, int64(1000), cfg.Exp)
 	assert.Equal(t, true, cfg.Base64Secret)
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default2", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default2", jwtAuth)
 	assert.Nil(t, cfg)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "not found")
@@ -789,7 +789,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "public")
@@ -797,7 +797,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "private")
@@ -805,7 +805,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "algorithm")
@@ -813,7 +813,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "exp")
@@ -821,7 +821,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "base64_secret")
@@ -829,7 +829,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "key")
@@ -837,7 +837,7 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerJwtAuthPlugin("default", jwtAuth)
+	cfg, err = tr.translateConsumerJwtAuthPluginV2beta3("default", jwtAuth)
 	assert.Nil(t, cfg)
 	assert.Equal(t, _errKeyNotFoundOrInvalid, err)
 
@@ -852,7 +852,7 @@ func TestTranslateConsumerWolfRBACPluginWithInPlaceValue(t *testing.T) {
 			Appid:  "test-app",
 		},
 	}
-	cfg, err := (&translator{}).translateConsumerWolfRBACPlugin("default", wolfRBAC)
+	cfg, err := (&translator{}).translateConsumerWolfRBACPluginV2beta3("default", wolfRBAC)
 	assert.Nil(t, err)
 	assert.Equal(t, "https://httpbin.org", cfg.Server)
 	assert.Equal(t, "test-app", cfg.Appid)
@@ -898,13 +898,13 @@ func TestTranslateConsumerWolfRBACWithSecretRef(t *testing.T) {
 	wolfRBAC := &configv2beta3.ApisixConsumerWolfRBAC{
 		SecretRef: &corev1.LocalObjectReference{Name: "jack-wolf-rbac"},
 	}
-	cfg, err := tr.translateConsumerWolfRBACPlugin("default", wolfRBAC)
+	cfg, err := tr.translateConsumerWolfRBACPluginV2beta3("default", wolfRBAC)
 	assert.Nil(t, err)
 	assert.Equal(t, "http://127.0.0.1:12180", cfg.Server)
 	assert.Equal(t, "test-app", cfg.Appid)
 	assert.Equal(t, "X-", cfg.HeaderPrefix)
 
-	cfg, err = tr.translateConsumerWolfRBACPlugin("default2", wolfRBAC)
+	cfg, err = tr.translateConsumerWolfRBACPluginV2beta3("default2", wolfRBAC)
 	assert.Nil(t, cfg)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "not found")
@@ -914,7 +914,7 @@ func TestTranslateConsumerWolfRBACWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerWolfRBACPlugin("default", wolfRBAC)
+	cfg, err = tr.translateConsumerWolfRBACPluginV2beta3("default", wolfRBAC)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "appid")
@@ -922,7 +922,7 @@ func TestTranslateConsumerWolfRBACWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerWolfRBACPlugin("default", wolfRBAC)
+	cfg, err = tr.translateConsumerWolfRBACPluginV2beta3("default", wolfRBAC)
 	assert.Nil(t, err)
 
 	delete(sec.Data, "header_prefix")
@@ -930,7 +930,7 @@ func TestTranslateConsumerWolfRBACWithSecretRef(t *testing.T) {
 	assert.Nil(t, err)
 	<-processCh
 
-	cfg, err = tr.translateConsumerWolfRBACPlugin("default", wolfRBAC)
+	cfg, err = tr.translateConsumerWolfRBACPluginV2beta3("default", wolfRBAC)
 	assert.Nil(t, err)
 
 	close(processCh)
diff --git a/pkg/kube/translation/translator.go b/pkg/kube/translation/translator.go
index 2acc5b4c..d0291abe 100644
--- a/pkg/kube/translation/translator.go
+++ b/pkg/kube/translation/translator.go
@@ -95,8 +95,11 @@ type Translator interface {
 	TranslateClusterConfigV2(*configv2.ApisixClusterConfig) (*apisixv1.GlobalRule, error)
 	// TranslateApisixConsumer translates the configv2beta3.APisixConsumer object into the APISIX Consumer
 	// resource.
-	TranslateApisixConsumer(*configv2beta3.ApisixConsumer) (*apisixv1.Consumer, error)
-	// TranslatePluginConfigV2beta3 translates the configv2beta3.ApisixPluginConfig object into several PluginConfig
+	TranslateApisixConsumerV2beta3(*configv2beta3.ApisixConsumer) (*apisixv1.Consumer, error)
+	// TranslateApisixConsumerV2 translates the configv2beta3.APisixConsumer object into the APISIX Consumer
+	// resource.
+	TranslateApisixConsumerV2(ac *configv2.ApisixConsumer) (*apisixv1.Consumer, error)
+	// TranslatePluginConfigV2beta3 translates the configv2.ApisixPluginConfig object into several PluginConfig
 	// resources.
 	TranslatePluginConfigV2beta3(*configv2beta3.ApisixPluginConfig) (*TranslateContext, error)
 	// TranslatePluginConfigV2beta3NotStrictly translates the configv2beta3.ApisixPluginConfig object into several PluginConfig