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

lingsamuel 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 bac9813e feat: support ApisixClusterConfig v2 (#977)
bac9813e is described below

commit bac9813e4c90a56dadba89808da2faa3d0834b79
Author: Sarasa Kisaragi <[email protected]>
AuthorDate: Thu May 12 16:54:53 2022 +0800

    feat: support ApisixClusterConfig v2 (#977)
    
    * feat: support ApisixClusterConfig v2
    
    Signed-off-by: Ling Samuel <[email protected]>
    
    * update
    
    Signed-off-by: Ling Samuel <[email protected]>
    
    * fmt
    
    Signed-off-by: Ling Samuel <[email protected]>
    
    * remove todo
    
    Signed-off-by: Ling Samuel <[email protected]>
---
 cmd/ingress/ingress.go                   |   1 +
 pkg/config/config.go                     |  44 ++---
 pkg/config/config_test.go                |  34 ++--
 pkg/ingress/apisix_cluster_config.go     | 284 ++++++++++++++++++++++---------
 pkg/ingress/controller.go                |  25 ++-
 pkg/ingress/status.go                    |  16 ++
 pkg/kube/apisix_cluster_config.go        | 169 ++++++++++++++++++
 pkg/kube/translation/global_rule.go      |  23 ++-
 pkg/kube/translation/global_rule_test.go |   2 +-
 pkg/kube/translation/translator.go       |   5 +-
 10 files changed, 478 insertions(+), 125 deletions(-)

diff --git a/cmd/ingress/ingress.go b/cmd/ingress/ingress.go
index a4d6cbf9..d0a24be5 100644
--- a/cmd/ingress/ingress.go
+++ b/cmd/ingress/ingress.go
@@ -163,6 +163,7 @@ For example, no available LB exists in the bare metal 
environment.`)
        cmd.PersistentFlags().StringVar(&cfg.Kubernetes.IngressVersion, 
"ingress-version", config.IngressNetworkingV1, "the supported ingress api group 
version, can be \"networking/v1beta1\", \"networking/v1\" (for Kubernetes 
version v1.19.0 or higher) and \"extensions/v1beta1\"")
        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().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 0d41f406..15b1d10a 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -87,17 +87,18 @@ type Config struct {
 
 // KubernetesConfig contains all Kubernetes related config items.
 type KubernetesConfig struct {
-       Kubeconfig          string             `json:"kubeconfig" 
yaml:"kubeconfig"`
-       ResyncInterval      types.TimeDuration `json:"resync_interval" 
yaml:"resync_interval"`
-       AppNamespaces       []string           `json:"app_namespaces" 
yaml:"app_namespaces"`
-       NamespaceSelector   []string           `json:"namespace_selector" 
yaml:"namespace_selector"`
-       ElectionID          string             `json:"election_id" 
yaml:"election_id"`
-       IngressClass        string             `json:"ingress_class" 
yaml:"ingress_class"`
-       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"`
-       ApisixTlsVersion    string             `json:"apisix_tls_version" 
yaml:"apisix_tls_version"`
-       EnableGatewayAPI    bool               `json:"enable_gateway_api" 
yaml:"enable_gateway_api"`
+       Kubeconfig                 string             `json:"kubeconfig" 
yaml:"kubeconfig"`
+       ResyncInterval             types.TimeDuration `json:"resync_interval" 
yaml:"resync_interval"`
+       AppNamespaces              []string           `json:"app_namespaces" 
yaml:"app_namespaces"`
+       NamespaceSelector          []string           
`json:"namespace_selector" yaml:"namespace_selector"`
+       ElectionID                 string             `json:"election_id" 
yaml:"election_id"`
+       IngressClass               string             `json:"ingress_class" 
yaml:"ingress_class"`
+       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"`
+       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"`
 }
 
 // APISIXConfig contains all APISIX related config items.
@@ -125,16 +126,17 @@ func NewDefaultConfig() *Config {
                KeyFilePath:           "/etc/webhook/certs/key.pem",
                EnableProfiling:       true,
                Kubernetes: KubernetesConfig{
-                       Kubeconfig:          "", // Use in-cluster 
configurations.
-                       ResyncInterval:      types.TimeDuration{Duration: 6 * 
time.Hour},
-                       AppNamespaces:       []string{v1.NamespaceAll},
-                       ElectionID:          IngressAPISIXLeader,
-                       IngressClass:        IngressClass,
-                       IngressVersion:      IngressNetworkingV1,
-                       ApisixRouteVersion:  ApisixRouteV2beta3,
-                       ApisixTlsVersion:    ApisixV2beta3,
-                       WatchEndpointSlices: false,
-                       EnableGatewayAPI:    false,
+                       Kubeconfig:                 "", // Use in-cluster 
configurations.
+                       ResyncInterval:             
types.TimeDuration{Duration: 6 * time.Hour},
+                       AppNamespaces:              []string{v1.NamespaceAll},
+                       ElectionID:                 IngressAPISIXLeader,
+                       IngressClass:               IngressClass,
+                       IngressVersion:             IngressNetworkingV1,
+                       ApisixRouteVersion:         ApisixRouteV2beta3,
+                       ApisixTlsVersion:           ApisixV2beta3,
+                       ApisixClusterConfigVersion: ApisixV2beta3,
+                       WatchEndpointSlices:        false,
+                       EnableGatewayAPI:           false,
                },
        }
 }
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 112ebd83..515d8e6a 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -38,14 +38,15 @@ func TestNewConfigFromFile(t *testing.T) {
                KeyFilePath:           "/etc/webhook/certs/key.pem",
                EnableProfiling:       true,
                Kubernetes: KubernetesConfig{
-                       ResyncInterval:     types.TimeDuration{Duration: 
time.Hour},
-                       Kubeconfig:         "/path/to/foo/baz",
-                       AppNamespaces:      []string{""},
-                       ElectionID:         "my-election-id",
-                       IngressClass:       IngressClass,
-                       IngressVersion:     IngressNetworkingV1,
-                       ApisixRouteVersion: ApisixRouteV2beta3,
-                       ApisixTlsVersion:   ApisixV2beta3,
+                       ResyncInterval:             
types.TimeDuration{Duration: time.Hour},
+                       Kubeconfig:                 "/path/to/foo/baz",
+                       AppNamespaces:              []string{""},
+                       ElectionID:                 "my-election-id",
+                       IngressClass:               IngressClass,
+                       IngressVersion:             IngressNetworkingV1,
+                       ApisixRouteVersion:         ApisixRouteV2beta3,
+                       ApisixTlsVersion:           ApisixV2beta3,
+                       ApisixClusterConfigVersion: ApisixV2beta3,
                },
                APISIX: APISIXConfig{
                        DefaultClusterName:     "default",
@@ -120,14 +121,15 @@ func TestConfigWithEnvVar(t *testing.T) {
                KeyFilePath:           "/etc/webhook/certs/key.pem",
                EnableProfiling:       true,
                Kubernetes: KubernetesConfig{
-                       ResyncInterval:     types.TimeDuration{Duration: 
time.Hour},
-                       Kubeconfig:         "",
-                       AppNamespaces:      []string{""},
-                       ElectionID:         "my-election-id",
-                       IngressClass:       IngressClass,
-                       IngressVersion:     IngressNetworkingV1,
-                       ApisixRouteVersion: ApisixRouteV2beta3,
-                       ApisixTlsVersion:   ApisixV2beta3,
+                       ResyncInterval:             
types.TimeDuration{Duration: time.Hour},
+                       Kubeconfig:                 "",
+                       AppNamespaces:              []string{""},
+                       ElectionID:                 "my-election-id",
+                       IngressClass:               IngressClass,
+                       IngressVersion:             IngressNetworkingV1,
+                       ApisixRouteVersion:         ApisixRouteV2beta3,
+                       ApisixTlsVersion:           ApisixV2beta3,
+                       ApisixClusterConfigVersion: ApisixV2beta3,
                },
                APISIX: APISIXConfig{
                        DefaultClusterName:     "default",
diff --git a/pkg/ingress/apisix_cluster_config.go 
b/pkg/ingress/apisix_cluster_config.go
index 7bed3d46..ecc33d0e 100644
--- a/pkg/ingress/apisix_cluster_config.go
+++ b/pkg/ingress/apisix_cluster_config.go
@@ -16,6 +16,7 @@ package ingress
 
 import (
        "context"
+       "fmt"
        "time"
 
        "go.uber.org/zap"
@@ -26,7 +27,8 @@ import (
        "k8s.io/client-go/util/workqueue"
 
        "github.com/apache/apisix-ingress-controller/pkg/apisix"
-       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"
 )
@@ -81,107 +83,204 @@ func (c *apisixClusterConfigController) runWorker(ctx 
context.Context) {
 }
 
 func (c *apisixClusterConfigController) sync(ctx context.Context, ev 
*types.Event) error {
-       key := ev.Object.(string)
+       event := ev.Object.(kube.ApisixClusterConfigEvent)
+       key := event.Key
        _, name, err := cache.SplitMetaNamespaceKey(key)
        if err != nil {
                log.Errorf("found ApisixClusterConfig resource with invalid 
meta key %s: %s", key, err)
                return err
        }
-       acc, err := c.controller.apisixClusterConfigLister.Get(name)
+
+       var multiVersioned kube.ApisixClusterConfig
+       switch event.GroupVersion {
+       case config.ApisixV2beta3:
+               multiVersioned, err = 
c.controller.apisixClusterConfigLister.V2beta3(name)
+       case config.ApisixV2:
+               multiVersioned, err = 
c.controller.apisixClusterConfigLister.V2(name)
+       default:
+               return fmt.Errorf("unsupported ApisixClusterConfig group 
version %s", event.GroupVersion)
+       }
+
        if err != nil {
                if !k8serrors.IsNotFound(err) {
-                       log.Errorf("failed to get ApisixClusterConfig %s: %s", 
key, err)
+                       log.Errorw("failed to get ApisixClusterConfig",
+                               zap.Error(err),
+                               zap.String("key", key),
+                               zap.String("version", event.GroupVersion),
+                       )
                        return err
                }
                if ev.Type != types.EventDelete {
-                       log.Warnf("ApisixClusterConfig %s was deleted before it 
can be delivered", key)
+                       log.Warnw("ApisixClusterConfig was deleted before it 
can be delivered",
+                               zap.String("key", key),
+                               zap.String("version", event.GroupVersion),
+                       )
                        return nil
                }
        }
        if ev.Type == types.EventDelete {
-               if acc != 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 ApisixClusterConfig delete 
event since the %s exists", key)
                        return nil
                }
-               acc = ev.Tombstone.(*configv2beta3.ApisixClusterConfig)
+               multiVersioned = ev.Tombstone.(kube.ApisixClusterConfig)
        }
 
-       // Currently we don't handle multiple cluster, so only process
-       // the default apisix cluster.
-       if acc.Name != c.controller.cfg.APISIX.DefaultClusterName {
-               log.Infow("ignore non-default apisix cluster config",
-                       zap.String("default_cluster_name", 
c.controller.cfg.APISIX.DefaultClusterName),
-                       zap.Any("ApisixClusterConfig", acc),
+       switch event.GroupVersion {
+       case config.ApisixV2beta3:
+               acc := multiVersioned.V2beta3()
+               // Currently we don't handle multiple cluster, so only process
+               // the default apisix cluster.
+               if acc.Name != c.controller.cfg.APISIX.DefaultClusterName {
+                       log.Infow("ignore non-default apisix cluster config",
+                               zap.String("default_cluster_name", 
c.controller.cfg.APISIX.DefaultClusterName),
+                               zap.Any("ApisixClusterConfig", acc),
+                       )
+                       return nil
+               }
+               // Cluster delete is dangerous.
+               // TODO handle delete?
+               if ev.Type == types.EventDelete {
+                       log.Error("ApisixClusterConfig delete event for default 
apisix cluster will be ignored")
+                       return nil
+               }
+
+               if acc.Spec.Admin != nil {
+                       clusterOpts := &apisix.ClusterOptions{
+                               Name:     acc.Name,
+                               BaseURL:  acc.Spec.Admin.BaseURL,
+                               AdminKey: acc.Spec.Admin.AdminKey,
+                       }
+                       log.Infow("updating cluster",
+                               zap.Any("opts", clusterOpts),
+                       )
+                       // TODO we may first call AddCluster.
+                       // Since now we already have the default cluster, we 
just call UpdateCluster.
+                       if err := c.controller.apisix.UpdateCluster(ctx, 
clusterOpts); err != nil {
+                               log.Errorw("failed to update cluster",
+                                       zap.String("cluster_name", acc.Name),
+                                       zap.Error(err),
+                                       zap.Any("opts", clusterOpts),
+                               )
+                               c.controller.recorderEvent(acc, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
+                               c.controller.recordStatus(acc, 
_resourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration())
+                               return err
+                       }
+               }
+
+               globalRule, err := 
c.controller.translator.TranslateClusterConfigV2beta3(acc)
+               if err != nil {
+                       log.Errorw("failed to translate ApisixClusterConfig",
+                               zap.Error(err),
+                               zap.String("key", key),
+                               zap.Any("object", acc),
+                       )
+                       c.controller.recorderEvent(acc, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
+                       c.controller.recordStatus(acc, _resourceSyncAborted, 
err, metav1.ConditionFalse, acc.GetGeneration())
+                       return err
+               }
+               log.Debugw("translated global_rule",
+                       zap.Any("object", globalRule),
                )
+
+               // TODO multiple cluster support
+               if ev.Type == types.EventAdd {
+                       _, err = 
c.controller.apisix.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
+               } else {
+                       _, err = 
c.controller.apisix.Cluster(acc.Name).GlobalRule().Update(ctx, globalRule)
+               }
+               if err != nil {
+                       log.Errorw("failed to reflect global_rule changes to 
apisix cluster",
+                               zap.Any("global_rule", globalRule),
+                               zap.Any("cluster", acc.Name),
+                       )
+                       c.controller.recorderEvent(acc, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
+                       c.controller.recordStatus(acc, _resourceSyncAborted, 
err, metav1.ConditionFalse, acc.GetGeneration())
+                       return err
+               }
+               c.controller.recorderEvent(acc, corev1.EventTypeNormal, 
_resourceSynced, nil)
+               c.controller.recordStatus(acc, _resourceSynced, nil, 
metav1.ConditionTrue, acc.GetGeneration())
                return nil
-       }
-       // Cluster delete is dangerous.
-       // TODO handle delete?
-       if ev.Type == types.EventDelete {
-               log.Error("ApisixClusterConfig delete event for default apisix 
cluster will be ignored")
-               return nil
-       }
+       case config.ApisixV2:
+               acc := multiVersioned.V2()
+               // Currently we don't handle multiple cluster, so only process
+               // the default apisix cluster.
+               if acc.Name != c.controller.cfg.APISIX.DefaultClusterName {
+                       log.Infow("ignore non-default apisix cluster config",
+                               zap.String("default_cluster_name", 
c.controller.cfg.APISIX.DefaultClusterName),
+                               zap.Any("ApisixClusterConfig", acc),
+                       )
+                       return nil
+               }
+               // Cluster delete is dangerous.
+               // TODO handle delete?
+               if ev.Type == types.EventDelete {
+                       log.Error("ApisixClusterConfig delete event for default 
apisix cluster will be ignored")
+                       return nil
+               }
 
-       if acc.Spec.Admin != nil {
-               clusterOpts := &apisix.ClusterOptions{
-                       Name:     acc.Name,
-                       BaseURL:  acc.Spec.Admin.BaseURL,
-                       AdminKey: acc.Spec.Admin.AdminKey,
+               if acc.Spec.Admin != nil {
+                       clusterOpts := &apisix.ClusterOptions{
+                               Name:     acc.Name,
+                               BaseURL:  acc.Spec.Admin.BaseURL,
+                               AdminKey: acc.Spec.Admin.AdminKey,
+                       }
+                       log.Infow("updating cluster",
+                               zap.Any("opts", clusterOpts),
+                       )
+                       // TODO we may first call AddCluster.
+                       // Since now we already have the default cluster, we 
just call UpdateCluster.
+                       if err := c.controller.apisix.UpdateCluster(ctx, 
clusterOpts); err != nil {
+                               log.Errorw("failed to update cluster",
+                                       zap.String("cluster_name", acc.Name),
+                                       zap.Error(err),
+                                       zap.Any("opts", clusterOpts),
+                               )
+                               c.controller.recorderEvent(acc, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
+                               c.controller.recordStatus(acc, 
_resourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration())
+                               return err
+                       }
                }
-               log.Infow("updating cluster",
-                       zap.Any("opts", clusterOpts),
-               )
-               // TODO we may first call AddCluster.
-               // Since now we already have the default cluster, we just call 
UpdateCluster.
-               if err := c.controller.apisix.UpdateCluster(ctx, clusterOpts); 
err != nil {
-                       log.Errorw("failed to update cluster",
-                               zap.String("cluster_name", acc.Name),
+
+               globalRule, err := 
c.controller.translator.TranslateClusterConfigV2(acc)
+               if err != nil {
+                       log.Errorw("failed to translate ApisixClusterConfig",
                                zap.Error(err),
-                               zap.Any("opts", clusterOpts),
+                               zap.String("key", key),
+                               zap.Any("object", acc),
                        )
                        c.controller.recorderEvent(acc, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
                        c.controller.recordStatus(acc, _resourceSyncAborted, 
err, metav1.ConditionFalse, acc.GetGeneration())
                        return err
                }
-       }
-
-       globalRule, err := c.controller.translator.TranslateClusterConfig(acc)
-       if err != nil {
-               // TODO add status
-               log.Errorw("failed to translate ApisixClusterConfig",
-                       zap.Error(err),
-                       zap.String("key", key),
-                       zap.Any("object", acc),
+               log.Debugw("translated global_rule",
+                       zap.Any("object", globalRule),
                )
-               c.controller.recorderEvent(acc, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
-               c.controller.recordStatus(acc, _resourceSyncAborted, err, 
metav1.ConditionFalse, acc.GetGeneration())
-               return err
-       }
-       log.Debugw("translated global_rule",
-               zap.Any("object", globalRule),
-       )
 
-       // TODO multiple cluster support
-       if ev.Type == types.EventAdd {
-               _, err = 
c.controller.apisix.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
-       } else {
-               _, err = 
c.controller.apisix.Cluster(acc.Name).GlobalRule().Update(ctx, globalRule)
-       }
-       if err != nil {
-               log.Errorw("failed to reflect global_rule changes to apisix 
cluster",
-                       zap.Any("global_rule", globalRule),
-                       zap.Any("cluster", acc.Name),
-               )
-               c.controller.recorderEvent(acc, corev1.EventTypeWarning, 
_resourceSyncAborted, err)
-               c.controller.recordStatus(acc, _resourceSyncAborted, err, 
metav1.ConditionFalse, acc.GetGeneration())
-               return err
+               // TODO multiple cluster support
+               if ev.Type == types.EventAdd {
+                       _, err = 
c.controller.apisix.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
+               } else {
+                       _, err = 
c.controller.apisix.Cluster(acc.Name).GlobalRule().Update(ctx, globalRule)
+               }
+               if err != nil {
+                       log.Errorw("failed to reflect global_rule changes to 
apisix cluster",
+                               zap.Any("global_rule", globalRule),
+                               zap.Any("cluster", acc.Name),
+                       )
+                       c.controller.recorderEvent(acc, 
corev1.EventTypeWarning, _resourceSyncAborted, err)
+                       c.controller.recordStatus(acc, _resourceSyncAborted, 
err, metav1.ConditionFalse, acc.GetGeneration())
+                       return err
+               }
+               c.controller.recorderEvent(acc, corev1.EventTypeNormal, 
_resourceSynced, nil)
+               c.controller.recordStatus(acc, _resourceSynced, nil, 
metav1.ConditionTrue, acc.GetGeneration())
+               return nil
+       default:
+               return fmt.Errorf("unsupported ApisixClusterConfig group 
version %s", event.GroupVersion)
        }
-       c.controller.recorderEvent(acc, corev1.EventTypeNormal, 
_resourceSynced, nil)
-       c.controller.recordStatus(acc, _resourceSynced, nil, 
metav1.ConditionTrue, acc.GetGeneration())
-       return nil
 }
 
 func (c *apisixClusterConfigController) handleSyncErr(obj interface{}, err 
error) {
@@ -209,6 +308,11 @@ func (c *apisixClusterConfigController) handleSyncErr(obj 
interface{}, err error
 }
 
 func (c *apisixClusterConfigController) onAdd(obj interface{}) {
+       acc, err := kube.NewApisixClusterConfig(obj)
+       if err != nil {
+               log.Errorw("found ApisixClusterConfig resource with bad type", 
zap.Error(err))
+               return
+       }
        key, err := cache.MetaNamespaceKeyFunc(obj)
        if err != nil {
                log.Errorf("found ApisixClusterConfig resource with bad meta 
key: %s", err.Error())
@@ -220,17 +324,28 @@ func (c *apisixClusterConfigController) onAdd(obj 
interface{}) {
        )
 
        c.workqueue.Add(&types.Event{
-               Type:   types.EventAdd,
-               Object: key,
+               Type: types.EventAdd,
+               Object: kube.ApisixClusterConfigEvent{
+                       Key:          key,
+                       GroupVersion: acc.GroupVersion(),
+               },
        })
 
        c.controller.MetricsCollector.IncrEvents("clusterConfig", "add")
 }
 
 func (c *apisixClusterConfigController) onUpdate(oldObj, newObj interface{}) {
-       prev := oldObj.(*configv2beta3.ApisixClusterConfig)
-       curr := newObj.(*configv2beta3.ApisixClusterConfig)
-       if prev.ResourceVersion >= curr.ResourceVersion {
+       prev, err := kube.NewApisixClusterConfig(oldObj)
+       if err != nil {
+               log.Errorw("found ApisixClusterConfig resource with bad type", 
zap.Error(err))
+               return
+       }
+       curr, err := kube.NewApisixClusterConfig(newObj)
+       if err != nil {
+               log.Errorw("found ApisixClusterConfig resource with bad type", 
zap.Error(err))
+               return
+       }
+       if prev.ResourceVersion() >= curr.ResourceVersion() {
                return
        }
        key, err := cache.MetaNamespaceKeyFunc(newObj)
@@ -244,21 +359,29 @@ func (c *apisixClusterConfigController) onUpdate(oldObj, 
newObj interface{}) {
        )
 
        c.workqueue.Add(&types.Event{
-               Type:   types.EventUpdate,
-               Object: key,
+               Type: types.EventUpdate,
+               Object: kube.ApisixClusterConfigEvent{
+                       Key:          key,
+                       OldObject:    prev,
+                       GroupVersion: curr.GroupVersion(),
+               },
        })
 
        c.controller.MetricsCollector.IncrEvents("clusterConfig", "update")
 }
 
 func (c *apisixClusterConfigController) onDelete(obj interface{}) {
-       acc, ok := obj.(*configv2beta3.ApisixClusterConfig)
-       if !ok {
+       acc, err := kube.NewApisixClusterConfig(obj)
+       if err != nil {
                tombstone, ok := obj.(*cache.DeletedFinalStateUnknown)
                if !ok {
                        return
                }
-               acc = tombstone.Obj.(*configv2beta3.ApisixClusterConfig)
+               acc, err = kube.NewApisixClusterConfig(tombstone)
+               if err != nil {
+                       log.Errorw("found ApisixClusterConfig resource with bad 
type", zap.Error(err))
+                       return
+               }
        }
 
        key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
@@ -270,8 +393,11 @@ func (c *apisixClusterConfigController) onDelete(obj 
interface{}) {
                zap.Any("final state", acc),
        )
        c.workqueue.Add(&types.Event{
-               Type:      types.EventDelete,
-               Object:    key,
+               Type: types.EventDelete,
+               Object: kube.ApisixClusterConfigEvent{
+                       Key:          key,
+                       GroupVersion: acc.GroupVersion(),
+               },
                Tombstone: acc,
        })
 
diff --git a/pkg/ingress/controller.go b/pkg/ingress/controller.go
index 6755dc51..c1afded2 100644
--- a/pkg/ingress/controller.go
+++ b/pkg/ingress/controller.go
@@ -111,7 +111,7 @@ type Controller struct {
        apisixRouteInformer         cache.SharedIndexInformer
        apisixTlsLister             kube.ApisixTlsLister
        apisixTlsInformer           cache.SharedIndexInformer
-       apisixClusterConfigLister   listersv2beta3.ApisixClusterConfigLister
+       apisixClusterConfigLister   kube.ApisixClusterConfigLister
        apisixClusterConfigInformer cache.SharedIndexInformer
        apisixConsumerInformer      cache.SharedIndexInformer
        apisixConsumerLister        listersv2beta3.ApisixConsumerLister
@@ -200,9 +200,10 @@ func NewController(cfg *config.Config) (*Controller, 
error) {
 
 func (c *Controller) initWhenStartLeading() {
        var (
-               ingressInformer     cache.SharedIndexInformer
-               apisixRouteInformer cache.SharedIndexInformer
-               apisixTlsInformer   cache.SharedIndexInformer
+               ingressInformer             cache.SharedIndexInformer
+               apisixRouteInformer         cache.SharedIndexInformer
+               apisixTlsInformer           cache.SharedIndexInformer
+               apisixClusterConfigInformer cache.SharedIndexInformer
        )
 
        kubeFactory := c.kubeClient.NewSharedIndexInformerFactory()
@@ -229,7 +230,10 @@ func (c *Controller) initWhenStartLeading() {
                apisixFactory.Apisix().V2beta3().ApisixTlses().Lister(),
                apisixFactory.Apisix().V2().ApisixTlses().Lister(),
        )
-       c.apisixClusterConfigLister = 
apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Lister()
+       c.apisixClusterConfigLister = kube.NewApisixClusterConfigLister(
+               
apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Lister(),
+               apisixFactory.Apisix().V2().ApisixClusterConfigs().Lister(),
+       )
        c.apisixConsumerLister = 
apisixFactory.Apisix().V2beta3().ApisixConsumers().Lister()
        c.apisixPluginConfigLister = kube.NewApisixPluginConfigLister(
                apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Lister(),
@@ -276,13 +280,22 @@ func (c *Controller) initWhenStartLeading() {
                panic(fmt.Errorf("unsupported ApisixTls version %s", 
c.cfg.Kubernetes.ApisixTlsVersion))
        }
 
+       switch c.cfg.Kubernetes.ApisixClusterConfigVersion {
+       case config.ApisixV2beta3:
+               apisixClusterConfigInformer = 
apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Informer()
+       case config.ApisixV2:
+               apisixClusterConfigInformer = 
apisixFactory.Apisix().V2().ApisixClusterConfigs().Informer()
+       default:
+               panic(fmt.Errorf("unsupported ApisixClusterConfig version %v", 
c.cfg.Kubernetes.ApisixClusterConfigVersion))
+       }
+
        c.namespaceInformer = kubeFactory.Core().V1().Namespaces().Informer()
        c.podInformer = kubeFactory.Core().V1().Pods().Informer()
        c.svcInformer = kubeFactory.Core().V1().Services().Informer()
        c.ingressInformer = ingressInformer
        c.apisixRouteInformer = apisixRouteInformer
        c.apisixUpstreamInformer = 
apisixFactory.Apisix().V2beta3().ApisixUpstreams().Informer()
-       c.apisixClusterConfigInformer = 
apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Informer()
+       c.apisixClusterConfigInformer = apisixClusterConfigInformer
        c.secretInformer = kubeFactory.Core().V1().Secrets().Informer()
        c.apisixTlsInformer = apisixTlsInformer
        c.apisixConsumerInformer = 
apisixFactory.Apisix().V2beta3().ApisixConsumers().Informer()
diff --git a/pkg/ingress/status.go b/pkg/ingress/status.go
index db9c4cf2..c2d090ed 100644
--- a/pkg/ingress/status.go
+++ b/pkg/ingress/status.go
@@ -210,6 +210,22 @@ func (c *Controller) recordStatus(at interface{}, reason 
string, err error, stat
                                )
                        }
                }
+       case *configv2.ApisixClusterConfig:
+               // 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().ApisixClusterConfigs().
+                               UpdateStatus(context.TODO(), v, 
metav1.UpdateOptions{}); errRecord != nil {
+                               log.Errorw("failed to record status change for 
ApisixClusterConfig",
+                                       zap.Error(errRecord),
+                                       zap.String("name", v.Name),
+                               )
+                       }
+               }
        case *networkingv1.Ingress:
                // set to status
                lbips, err := c.ingressLBStatusIPs()
diff --git a/pkg/kube/apisix_cluster_config.go 
b/pkg/kube/apisix_cluster_config.go
new file mode 100644
index 00000000..9eb8ecee
--- /dev/null
+++ b/pkg/kube/apisix_cluster_config.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 (
+       "fmt"
+
+       "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"
+)
+
+// ApisixClusterConfigLister is an encapsulation for the lister of 
ApisixClusterConfig,
+// it aims at to be compatible with different ApisixClusterConfig versions.
+type ApisixClusterConfigLister interface {
+       // V2beta3 gets the ApisixClusterConfig in apisix.apache.org/v2beta3.
+       V2beta3(string) (ApisixClusterConfig, error)
+       // V2 gets the ApisixClusterConfig in apisix.apache.org/v2.
+       V2(string) (ApisixClusterConfig, error)
+}
+
+// ApisixClusterConfigInformer is an encapsulation for the informer of 
ApisixClusterConfig,
+// it aims at to be compatible with different ApisixClusterConfig versions.
+type ApisixClusterConfigInformer interface {
+       Run(chan struct{})
+}
+
+// ApisixClusterConfig is an encapsulation for ApisixClusterConfig resource 
with different
+// versions, for now, they are apisix.apache.org/v1 and 
apisix.apache.org/v2alpha1
+type ApisixClusterConfig interface {
+       // GroupVersion returns the api group version of the
+       // real ApisixClusterConfig.
+       GroupVersion() string
+       // V2beta3 returns the ApisixClusterConfig in 
apisix.apache.org/v2beta3, the real
+       // ApisixClusterConfig must be in this group version, otherwise will 
panic.
+       V2beta3() *configv2beta3.ApisixClusterConfig
+       // V2 returns the ApisixClusterConfig in apisix.apache.org/v2, the real
+       // ApisixClusterConfig must be in this group version, otherwise will 
panic.
+       V2() *configv2.ApisixClusterConfig
+       // ResourceVersion returns the the resource version field inside
+       // the real ApisixClusterConfig.
+       ResourceVersion() string
+}
+
+// ApisixClusterConfigEvent contains the ApisixClusterConfig key 
(namespace/name)
+// and the group version message.
+type ApisixClusterConfigEvent struct {
+       Key          string
+       OldObject    ApisixClusterConfig
+       GroupVersion string
+}
+
+type apisixClusterConfig struct {
+       groupVersion string
+       v2beta3      *configv2beta3.ApisixClusterConfig
+       v2           *configv2.ApisixClusterConfig
+}
+
+func (acc *apisixClusterConfig) V2beta3() *configv2beta3.ApisixClusterConfig {
+       if acc.groupVersion != config.ApisixV2beta3 {
+               panic("not a apisix.apache.org/v2beta3 apisixClusterConfig")
+       }
+       return acc.v2beta3
+}
+
+func (acc *apisixClusterConfig) V2() *configv2.ApisixClusterConfig {
+       if acc.groupVersion != config.ApisixV2 {
+               panic("not a apisix.apache.org/v2 apisixClusterConfig")
+       }
+       return acc.v2
+}
+
+func (acc *apisixClusterConfig) GroupVersion() string {
+       return acc.groupVersion
+}
+
+func (acc *apisixClusterConfig) ResourceVersion() string {
+       if acc.groupVersion == config.ApisixV2beta3 {
+               return acc.V2beta3().ResourceVersion
+       }
+       return acc.V2().ResourceVersion
+}
+
+type apisixClusterConfigLister struct {
+       v2beta3Lister listersv2beta3.ApisixClusterConfigLister
+       v2Lister      listersv2.ApisixClusterConfigLister
+}
+
+func (l *apisixClusterConfigLister) V2beta3(name string) (ApisixClusterConfig, 
error) {
+       acc, err := l.v2beta3Lister.Get(name)
+       if err != nil {
+               return nil, err
+       }
+       return &apisixClusterConfig{
+               groupVersion: config.ApisixV2beta3,
+               v2beta3:      acc,
+       }, nil
+}
+
+func (l *apisixClusterConfigLister) V2(name string) (ApisixClusterConfig, 
error) {
+       acc, err := l.v2Lister.Get(name)
+       if err != nil {
+               return nil, err
+       }
+       return &apisixClusterConfig{
+               groupVersion: config.ApisixV2,
+               v2:           acc,
+       }, nil
+}
+
+// MustNewApisixClusterConfig creates a kube.ApisixClusterConfig object 
according to the
+// type of obj.
+func MustNewApisixClusterConfig(obj interface{}) ApisixClusterConfig {
+       switch acc := obj.(type) {
+       case *configv2beta3.ApisixClusterConfig:
+               return &apisixClusterConfig{
+                       groupVersion: config.ApisixV2beta3,
+                       v2beta3:      acc,
+               }
+       case *configv2.ApisixClusterConfig:
+               return &apisixClusterConfig{
+                       groupVersion: config.ApisixV2,
+                       v2:           acc,
+               }
+       default:
+               panic("invalid ApisixClusterConfig type")
+       }
+}
+
+// NewApisixClusterConfig creates a kube.ApisixClusterConfig object according 
to the
+// type of obj. It returns nil and the error reason when the
+// type assertion fails.
+func NewApisixClusterConfig(obj interface{}) (ApisixClusterConfig, error) {
+       switch acc := obj.(type) {
+       case *configv2beta3.ApisixClusterConfig:
+               return &apisixClusterConfig{
+                       groupVersion: config.ApisixV2beta3,
+                       v2beta3:      acc,
+               }, nil
+       case *configv2.ApisixClusterConfig:
+               return &apisixClusterConfig{
+                       groupVersion: config.ApisixV2,
+                       v2:           acc,
+               }, nil
+       default:
+               return nil, fmt.Errorf("invalid ApisixClusterConfig type %T", 
acc)
+       }
+}
+
+func NewApisixClusterConfigLister(v2beta3 
listersv2beta3.ApisixClusterConfigLister, v2 
listersv2.ApisixClusterConfigLister) ApisixClusterConfigLister {
+       return &apisixClusterConfigLister{
+               v2beta3Lister: v2beta3,
+               v2Lister:      v2,
+       }
+}
diff --git a/pkg/kube/translation/global_rule.go 
b/pkg/kube/translation/global_rule.go
index 7fc1eaef..d59cd982 100644
--- a/pkg/kube/translation/global_rule.go
+++ b/pkg/kube/translation/global_rule.go
@@ -16,6 +16,7 @@ package translation
 
 import (
        "github.com/apache/apisix-ingress-controller/pkg/id"
+       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"
 )
@@ -26,7 +27,27 @@ type skywalkingPluginConfig struct {
        SampleRatio float64 `json:"sample_ratio,omitempty"`
 }
 
-func (t *translator) TranslateClusterConfig(acc 
*configv2beta3.ApisixClusterConfig) (*apisixv1.GlobalRule, error) {
+func (t *translator) TranslateClusterConfigV2beta3(acc 
*configv2beta3.ApisixClusterConfig) (*apisixv1.GlobalRule, error) {
+       globalRule := &apisixv1.GlobalRule{
+               ID:      id.GenID(acc.Name),
+               Plugins: make(apisixv1.Plugins),
+       }
+
+       if acc.Spec.Monitoring != nil {
+               if acc.Spec.Monitoring.Prometheus.Enable {
+                       globalRule.Plugins["prometheus"] = 
&prometheusPluginConfig{}
+               }
+               if acc.Spec.Monitoring.Skywalking.Enable {
+                       globalRule.Plugins["skywalking"] = 
&skywalkingPluginConfig{
+                               SampleRatio: 
acc.Spec.Monitoring.Skywalking.SampleRatio,
+                       }
+               }
+       }
+
+       return globalRule, nil
+}
+
+func (t *translator) TranslateClusterConfigV2(acc 
*configv2.ApisixClusterConfig) (*apisixv1.GlobalRule, error) {
        globalRule := &apisixv1.GlobalRule{
                ID:      id.GenID(acc.Name),
                Plugins: make(apisixv1.Plugins),
diff --git a/pkg/kube/translation/global_rule_test.go 
b/pkg/kube/translation/global_rule_test.go
index 8a584ac4..93cbc5fe 100644
--- a/pkg/kube/translation/global_rule_test.go
+++ b/pkg/kube/translation/global_rule_test.go
@@ -44,7 +44,7 @@ func TestTranslateClusterConfig(t *testing.T) {
                        },
                },
        }
-       gr, err := tr.TranslateClusterConfig(acc)
+       gr, err := tr.TranslateClusterConfigV2beta3(acc)
        assert.Nil(t, err, "translating ApisixClusterConfig")
        assert.Equal(t, gr.ID, id.GenID("qa-apisix"), "checking global_rule id")
        assert.Len(t, gr.Plugins, 2)
diff --git a/pkg/kube/translation/translator.go 
b/pkg/kube/translation/translator.go
index c5217aa3..2acc5b4c 100644
--- a/pkg/kube/translation/translator.go
+++ b/pkg/kube/translation/translator.go
@@ -89,7 +89,10 @@ type Translator interface {
        TranslateSSLV2(*configv2.ApisixTls) (*apisixv1.Ssl, error)
        // TranslateClusterConfig translates the 
configv2beta3.ApisixClusterConfig object into the APISIX
        // Global Rule resource.
-       TranslateClusterConfig(*configv2beta3.ApisixClusterConfig) 
(*apisixv1.GlobalRule, error)
+       TranslateClusterConfigV2beta3(*configv2beta3.ApisixClusterConfig) 
(*apisixv1.GlobalRule, error)
+       // TranslateClusterConfigV2 translates the configv2.ApisixClusterConfig 
object into the APISIX
+       // Global Rule resource.
+       TranslateClusterConfigV2(*configv2.ApisixClusterConfig) 
(*apisixv1.GlobalRule, error)
        // TranslateApisixConsumer translates the configv2beta3.APisixConsumer 
object into the APISIX Consumer
        // resource.
        TranslateApisixConsumer(*configv2beta3.ApisixConsumer) 
(*apisixv1.Consumer, error)

Reply via email to