From f6f0a3b5552ba8fda556e0edb9296c1c0a4c3e31 Mon Sep 17 00:00:00 2001 From: Sarasa Kisaragi Date: Mon, 23 May 2022 17:09:56 +0800 Subject: [PATCH] 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(-) create mode 100644 pkg/kube/apisix_consumer.go diff --git a/cmd/ingress/ingress.go b/cmd/ingress/ingress.go index d0a24be56b..daed16372a 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 15b1d10a62..2641ef5d0e 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 515d8e6ae6..311afd50a7 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 edc9b78e41..8a456a7055 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 6d2f560d98..6ab081e46d 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 c1afded289..33c273c8e7 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 c2d090ed34..604227a00e 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 0000000000..a9d188d9a4 --- /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 04525799b1..982b741fe0 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 775e2a3a2c..a875c8a694 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 c2a9b1096c..5b532932ae 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 a6cad20fe6..94cbc9ee7e 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 2acc5b4c42..d0291abe77 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