You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by zh...@apache.org on 2022/08/10 13:42:18 UTC
[apisix-ingress-controller] branch master updated: feat: Restruct pkg/ingress (#1204)
This is an automated email from the ASF dual-hosted git repository.
zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
The following commit(s) were added to refs/heads/master by this push:
new d32c7281 feat: Restruct pkg/ingress (#1204)
d32c7281 is described below
commit d32c728139a706bbad155a5e58514a3e59a841e4
Author: Sarasa Kisaragi <li...@gmail.com>
AuthorDate: Wed Aug 10 21:42:13 2022 +0800
feat: Restruct pkg/ingress (#1204)
---
cmd/ingress/ingress.go | 4 +-
pkg/config/config.go | 2 -
pkg/config/config_test.go | 30 +-
pkg/ingress/controller.go | 813 ------------
pkg/ingress/status.go | 343 -----
pkg/kube/translation/ingress_test.go | 1376 --------------------
pkg/kube/translation/translator.go | 426 ------
pkg/kube/translation/util.go | 263 ----
.../apisix}/apisix_cluster_config.go | 175 ++-
.../apisix}/apisix_consumer.go | 157 ++-
.../apisix/apisix_plugin_config.go} | 166 ++-
pkg/{ingress => providers/apisix}/apisix_route.go | 235 +++-
pkg/{ingress => providers/apisix}/apisix_tls.go | 178 ++-
.../apisix}/apisix_upstream.go | 192 ++-
pkg/providers/apisix/provider.go | 202 +++
.../apisix/provider_init.go} | 76 +-
.../apisix/translation/apisix_cluster_config.go} | 0
.../translation/apisix_cluster_config_test.go} | 0
.../apisix}/translation/apisix_consumer.go | 0
.../apisix}/translation/apisix_consumer_test.go | 0
.../apisix/translation/apisix_plugin.go} | 9 +-
.../apisix/translation/apisix_plugin_test.go} | 72 +-
.../apisix}/translation/apisix_pluginconfig.go | 17 +-
.../translation/apisix_pluginconfig_test.go | 0
.../apisix}/translation/apisix_route.go | 271 +++-
.../apisix}/translation/apisix_route_test.go | 11 +-
.../apisix}/translation/apisix_ssl.go | 64 +-
.../apisix/translation/apisix_upstream.go | 48 +
pkg/providers/apisix/translation/translator.go | 106 ++
pkg/providers/controller.go | 500 +++++++
pkg/{ingress => providers}/gateway/gateway.go | 2 +-
.../gateway/gateway_class.go | 0
.../gateway/gateway_httproute.go | 4 +-
.../gateway/gateway_tlsroute.go | 4 +-
pkg/{ingress => providers}/gateway/provider.go | 18 +-
.../gateway/translation/gateway.go | 2 +-
.../gateway/translation/gateway_httproute.go | 6 +-
.../gateway/translation/gateway_httproute_test.go | 2 +-
.../gateway/translation/gateway_tlsroute.go | 6 +-
.../gateway/translation/translator.go | 4 +-
pkg/{ingress => providers}/gateway/types/types.go | 0
pkg/{ => providers}/ingress/ingress.go | 173 ++-
pkg/{ => providers}/ingress/ingress_test.go | 7 +-
pkg/providers/ingress/provider.go | 118 ++
.../ingress}/translation/annotations.go | 4 +-
.../translation/annotations/authorization.go | 0
.../ingress}/translation/annotations/cors.go | 0
.../ingress}/translation/annotations/cors_test.go | 0
.../ingress}/translation/annotations/csrf.go | 0
.../translation/annotations/forward_auth.go | 0
.../translation/annotations/forward_auth_test.go | 0
.../translation/annotations/iprestriction.go | 0
.../translation/annotations/iprestriction_test.go | 0
.../ingress}/translation/annotations/redirect.go | 0
.../ingress}/translation/annotations/rewrite.go | 0
.../ingress}/translation/annotations/types.go | 0
.../ingress/translation/translator.go} | 160 ++-
pkg/providers/k8s/endpoint/base.go | 133 ++
.../k8s/endpoint}/endpoint.go | 57 +-
.../k8s/endpoint}/endpointslice.go | 71 +-
pkg/providers/k8s/endpoint/provider.go | 77 ++
.../k8s}/namespace/namespace.go | 0
.../k8s/namespace/namespace_provider.go} | 24 +-
.../k8s/namespace/namespace_provider_mock.go} | 6 +-
pkg/{ingress => providers/k8s/pod}/pod.go | 45 +-
pkg/{ingress => providers/k8s/pod}/pod_test.go | 57 +-
pkg/providers/k8s/pod/provider.go | 75 ++
pkg/providers/k8s/provider.go | 80 ++
pkg/{ingress => providers/k8s}/secret.go | 196 ++-
.../translation/apisix_upstream.go | 340 ++---
.../translation/apisix_upstream_test.go | 240 ++--
pkg/{kube => providers}/translation/context.go | 10 +-
.../translation/context_test.go | 0
pkg/providers/translation/service.go | 249 ++++
pkg/providers/translation/translator.go | 89 ++
.../translation/translator_test.go | 60 +-
pkg/providers/translation/util.go | 88 ++
pkg/{kube => providers}/translation/util_test.go | 4 +-
pkg/providers/types/types.go | 183 +++
pkg/{ingress => providers}/utils/executor.go | 0
pkg/{ingress => providers}/utils/ingress_status.go | 0
pkg/{ingress => providers}/utils/manifest.go | 0
pkg/{ingress => providers}/utils/manifest_test.go | 0
pkg/providers/utils/status.go | 66 +
pkg/{ingress => providers}/utils/string.go | 0
pkg/types/pod.go | 2 +-
test/e2e/scaffold/ingress.go | 189 +--
test/e2e/scaffold/scaffold.go | 2 +-
88 files changed, 4178 insertions(+), 4411 deletions(-)
diff --git a/cmd/ingress/ingress.go b/cmd/ingress/ingress.go
index dcbb7264..cf732566 100644
--- a/cmd/ingress/ingress.go
+++ b/cmd/ingress/ingress.go
@@ -27,8 +27,8 @@ import (
"github.com/spf13/cobra"
"github.com/apache/apisix-ingress-controller/pkg/config"
- controller "github.com/apache/apisix-ingress-controller/pkg/ingress"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ controller "github.com/apache/apisix-ingress-controller/pkg/providers"
"github.com/apache/apisix-ingress-controller/pkg/version"
)
@@ -161,8 +161,6 @@ For example, no available LB exists in the bare metal environment.`)
cmd.PersistentFlags().StringVar(&cfg.Kubernetes.IngressClass, "ingress-class", config.IngressClass, "the class of an Ingress object is set using the field IngressClassName in Kubernetes clusters version v1.18.0 or higher or the annotation \"kubernetes.io/ingress.class\" (deprecated)")
cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ElectionID, "election-id", config.IngressAPISIXLeader, "election id used for campaign the controller leader")
cmd.PersistentFlags().StringVar(&cfg.Kubernetes.IngressVersion, "ingress-version", config.IngressNetworkingV1, "the supported ingress api group version, can be \"networking/v1beta1\", \"networking/v1\" (for Kubernetes version v1.19.0 or higher) and \"extensions/v1beta1\"")
- cmd.PersistentFlags().StringVar(&cfg.Kubernetes.ApisixRouteVersion, "apisix-route-version", config.DefaultAPIVersion, "the supported apisixroute api group version, can be \"apisix.apache.org/v2beta2\" or \"apisix.apache.org/v2beta3\" or \"apisix.apache.org/v2\"")
- _ = cmd.PersistentFlags().MarkDeprecated("apisix-route-version", "will be removed in the next version, please use --api-version instead")
cmd.PersistentFlags().StringVar(&cfg.Kubernetes.APIVersion, "api-version", config.DefaultAPIVersion, config.APIVersionDescribe)
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")
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 04bb64bf..4e061b6c 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -99,7 +99,6 @@ type KubernetesConfig struct {
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"`
APIVersion string `json:"api_version" yaml:"api_version"`
EnableGatewayAPI bool `json:"enable_gateway_api" yaml:"enable_gateway_api"`
}
@@ -136,7 +135,6 @@ func NewDefaultConfig() *Config {
ElectionID: IngressAPISIXLeader,
IngressClass: IngressClass,
IngressVersion: IngressNetworkingV1,
- ApisixRouteVersion: DefaultAPIVersion,
APIVersion: DefaultAPIVersion,
WatchEndpointSlices: false,
EnableGatewayAPI: false,
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 9c305c7c..c448d440 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -39,14 +39,13 @@ func TestNewConfigFromFile(t *testing.T) {
EnableProfiling: true,
ApisixResourceSyncInterval: types.TimeDuration{Duration: 200 * time.Second},
Kubernetes: KubernetesConfig{
- ResyncInterval: types.TimeDuration{Duration: time.Hour},
- Kubeconfig: "/path/to/foo/baz",
- AppNamespaces: []string{""},
- ElectionID: "my-election-id",
- IngressClass: IngressClass,
- IngressVersion: IngressNetworkingV1,
- ApisixRouteVersion: DefaultAPIVersion,
- APIVersion: DefaultAPIVersion,
+ ResyncInterval: types.TimeDuration{Duration: time.Hour},
+ Kubeconfig: "/path/to/foo/baz",
+ AppNamespaces: []string{""},
+ ElectionID: "my-election-id",
+ IngressClass: IngressClass,
+ IngressVersion: IngressNetworkingV1,
+ APIVersion: DefaultAPIVersion,
},
APISIX: APISIXConfig{
DefaultClusterName: "default",
@@ -124,14 +123,13 @@ func TestConfigWithEnvVar(t *testing.T) {
EnableProfiling: true,
ApisixResourceSyncInterval: types.TimeDuration{Duration: 200 * time.Second},
Kubernetes: KubernetesConfig{
- ResyncInterval: types.TimeDuration{Duration: time.Hour},
- Kubeconfig: "",
- AppNamespaces: []string{""},
- ElectionID: "my-election-id",
- IngressClass: IngressClass,
- IngressVersion: IngressNetworkingV1,
- ApisixRouteVersion: DefaultAPIVersion,
- APIVersion: DefaultAPIVersion,
+ ResyncInterval: types.TimeDuration{Duration: time.Hour},
+ Kubeconfig: "",
+ AppNamespaces: []string{""},
+ ElectionID: "my-election-id",
+ IngressClass: IngressClass,
+ IngressVersion: IngressNetworkingV1,
+ APIVersion: DefaultAPIVersion,
},
APISIX: APISIXConfig{
DefaultClusterName: "default",
diff --git a/pkg/ingress/controller.go b/pkg/ingress/controller.go
deleted file mode 100644
index 5a1a41d1..00000000
--- a/pkg/ingress/controller.go
+++ /dev/null
@@ -1,813 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package ingress
-
-import (
- "context"
- "fmt"
- "os"
- "sync"
- "time"
-
- "go.uber.org/zap"
- v1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- utilruntime "k8s.io/apimachinery/pkg/util/runtime"
- "k8s.io/client-go/kubernetes/scheme"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- listerscorev1 "k8s.io/client-go/listers/core/v1"
- "k8s.io/client-go/tools/cache"
- "k8s.io/client-go/tools/leaderelection"
- "k8s.io/client-go/tools/leaderelection/resourcelock"
- "k8s.io/client-go/tools/record"
-
- "github.com/apache/apisix-ingress-controller/pkg/api"
- "github.com/apache/apisix-ingress-controller/pkg/apisix"
- apisixcache "github.com/apache/apisix-ingress-controller/pkg/apisix/cache"
- "github.com/apache/apisix-ingress-controller/pkg/config"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/gateway"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/namespace"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
- "github.com/apache/apisix-ingress-controller/pkg/kube"
- 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"
- apisixscheme "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/scheme"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
- "github.com/apache/apisix-ingress-controller/pkg/log"
- "github.com/apache/apisix-ingress-controller/pkg/metrics"
- "github.com/apache/apisix-ingress-controller/pkg/types"
- apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
-)
-
-const (
- // _component is used for event component
- _component = "ApisixIngress"
- // _resourceSynced is used when a resource is synced successfully
- _resourceSynced = "ResourcesSynced"
- // _messageResourceSynced is used to specify controller
- _messageResourceSynced = "%s synced successfully"
- // _resourceSyncAborted is used when a resource synced failed
- _resourceSyncAborted = "ResourceSyncAborted"
- // _messageResourceFailed is used to report error
- _messageResourceFailed = "%s synced failed, with error: %s"
- // minimum interval for ingress sync to APISIX
- _mininumApisixResourceSyncInterval = 60 * time.Second
-)
-
-// Controller is the ingress apisix controller object.
-type Controller struct {
- name string
- namespace string
- cfg *config.Config
- apisix apisix.APISIX
- podCache types.PodCache
- translator translation.Translator
- apiServer *api.Server
- MetricsCollector metrics.Collector
- kubeClient *kube.KubeClient
- // recorder event
- recorder record.EventRecorder
- // this map enrolls which ApisixTls objects refer to a Kubernetes
- // Secret object.
- // type: Map<SecretKey, Map<ApisixTlsKey, ApisixTls>>
- // SecretKey is `namespace_name`, ApisixTlsKey is kube style meta key: `namespace/name`
- secretSSLMap *sync.Map
-
- // leaderContextCancelFunc will be called when apisix-ingress-controller
- // decides to give up its leader role.
- leaderContextCancelFunc context.CancelFunc
-
- // common informers and listers
- podInformer cache.SharedIndexInformer
- podLister listerscorev1.PodLister
- epInformer cache.SharedIndexInformer
- epLister kube.EndpointLister
- svcInformer cache.SharedIndexInformer
- svcLister listerscorev1.ServiceLister
- ingressLister kube.IngressLister
- ingressInformer cache.SharedIndexInformer
- secretInformer cache.SharedIndexInformer
- secretLister listerscorev1.SecretLister
- apisixUpstreamInformer cache.SharedIndexInformer
- apisixUpstreamLister kube.ApisixUpstreamLister
- apisixRouteLister kube.ApisixRouteLister
- apisixRouteInformer cache.SharedIndexInformer
- apisixTlsLister kube.ApisixTlsLister
- apisixTlsInformer cache.SharedIndexInformer
- apisixClusterConfigLister kube.ApisixClusterConfigLister
- apisixClusterConfigInformer cache.SharedIndexInformer
- apisixConsumerInformer cache.SharedIndexInformer
- apisixConsumerLister kube.ApisixConsumerLister
- apisixPluginConfigInformer cache.SharedIndexInformer
- apisixPluginConfigLister kube.ApisixPluginConfigLister
-
- // resource controllers
- podController *podController
- endpointsController *endpointsController
- endpointSliceController *endpointSliceController
- ingressController *ingressController
- secretController *secretController
-
- namespaceProvider namespace.WatchingProvider
- gatewayProvider *gateway.Provider
-
- apisixUpstreamController *apisixUpstreamController
- apisixRouteController *apisixRouteController
- apisixTlsController *apisixTlsController
- apisixClusterConfigController *apisixClusterConfigController
- apisixConsumerController *apisixConsumerController
- apisixPluginConfigController *apisixPluginConfigController
-}
-
-// NewController creates an ingress apisix controller object.
-func NewController(cfg *config.Config) (*Controller, error) {
- podName := os.Getenv("POD_NAME")
- podNamespace := os.Getenv("POD_NAMESPACE")
- if podNamespace == "" {
- podNamespace = "default"
- }
- client, err := apisix.NewClient()
- if err != nil {
- return nil, err
- }
-
- kubeClient, err := kube.NewKubeClient(cfg)
- if err != nil {
- return nil, err
- }
-
- apiSrv, err := api.NewServer(cfg)
- if err != nil {
- return nil, err
- }
-
- // recorder
- utilruntime.Must(apisixscheme.AddToScheme(scheme.Scheme))
- eventBroadcaster := record.NewBroadcaster()
- eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeClient.Client.CoreV1().Events("")})
-
- c := &Controller{
- name: podName,
- namespace: podNamespace,
- cfg: cfg,
- apiServer: apiSrv,
- apisix: client,
- MetricsCollector: metrics.NewPrometheusCollector(),
- kubeClient: kubeClient,
- secretSSLMap: new(sync.Map),
- recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: _component}),
-
- podCache: types.NewPodCache(),
- }
- return c, nil
-}
-
-func (c *Controller) initWhenStartLeading() {
- var (
- ingressInformer cache.SharedIndexInformer
- apisixRouteInformer cache.SharedIndexInformer
- apisixPluginConfigInformer cache.SharedIndexInformer
- apisixTlsInformer cache.SharedIndexInformer
- apisixClusterConfigInformer cache.SharedIndexInformer
- apisixConsumerInformer cache.SharedIndexInformer
- apisixUpstreamInformer cache.SharedIndexInformer
- )
-
- kubeFactory := c.kubeClient.NewSharedIndexInformerFactory()
- apisixFactory := c.kubeClient.NewAPISIXSharedIndexInformerFactory()
-
- c.podLister = kubeFactory.Core().V1().Pods().Lister()
- c.epLister, c.epInformer = kube.NewEndpointListerAndInformer(kubeFactory, c.cfg.Kubernetes.WatchEndpointSlices)
- c.svcLister = kubeFactory.Core().V1().Services().Lister()
- c.ingressLister = kube.NewIngressLister(
- kubeFactory.Networking().V1().Ingresses().Lister(),
- kubeFactory.Networking().V1beta1().Ingresses().Lister(),
- kubeFactory.Extensions().V1beta1().Ingresses().Lister(),
- )
- c.secretLister = kubeFactory.Core().V1().Secrets().Lister()
- c.apisixRouteLister = kube.NewApisixRouteLister(
- apisixFactory.Apisix().V2beta2().ApisixRoutes().Lister(),
- apisixFactory.Apisix().V2beta3().ApisixRoutes().Lister(),
- apisixFactory.Apisix().V2().ApisixRoutes().Lister(),
- )
- c.apisixUpstreamLister = kube.NewApisixUpstreamLister(
- apisixFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixFactory.Apisix().V2().ApisixUpstreams().Lister(),
- )
- c.apisixTlsLister = kube.NewApisixTlsLister(
- apisixFactory.Apisix().V2beta3().ApisixTlses().Lister(),
- apisixFactory.Apisix().V2().ApisixTlses().Lister(),
- )
- c.apisixClusterConfigLister = kube.NewApisixClusterConfigLister(
- apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Lister(),
- apisixFactory.Apisix().V2().ApisixClusterConfigs().Lister(),
- )
- c.apisixConsumerLister = kube.NewApisixConsumerLister(
- apisixFactory.Apisix().V2beta3().ApisixConsumers().Lister(),
- apisixFactory.Apisix().V2().ApisixConsumers().Lister(),
- )
- c.apisixPluginConfigLister = kube.NewApisixPluginConfigLister(
- apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Lister(),
- apisixFactory.Apisix().V2().ApisixPluginConfigs().Lister(),
- )
-
- c.translator = translation.NewTranslator(&translation.TranslatorOptions{
- PodCache: c.podCache,
- PodLister: c.podLister,
- EndpointLister: c.epLister,
- ServiceLister: c.svcLister,
- ApisixUpstreamLister: c.apisixUpstreamLister,
- SecretLister: c.secretLister,
- UseEndpointSlices: c.cfg.Kubernetes.WatchEndpointSlices,
- APIVersion: c.cfg.Kubernetes.APIVersion,
- Apisix: c.apisix,
- ClusterName: c.cfg.APISIX.DefaultClusterName,
- })
-
- switch c.cfg.Kubernetes.APIVersion {
- case config.ApisixV2beta3:
- apisixUpstreamInformer = apisixFactory.Apisix().V2beta3().ApisixUpstreams().Informer()
- // to do ApisixRoute
- apisixPluginConfigInformer = apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Informer()
- apisixTlsInformer = apisixFactory.Apisix().V2beta3().ApisixTlses().Informer()
- apisixConsumerInformer = apisixFactory.Apisix().V2beta3().ApisixConsumers().Informer()
- apisixClusterConfigInformer = apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Informer()
- case config.ApisixV2:
- apisixUpstreamInformer = apisixFactory.Apisix().V2().ApisixUpstreams().Informer()
- // to do ApisixRoute
- apisixPluginConfigInformer = apisixFactory.Apisix().V2().ApisixPluginConfigs().Informer()
- apisixTlsInformer = apisixFactory.Apisix().V2().ApisixTlses().Informer()
- apisixConsumerInformer = apisixFactory.Apisix().V2().ApisixConsumers().Informer()
- apisixClusterConfigInformer = apisixFactory.Apisix().V2().ApisixClusterConfigs().Informer()
- default:
- panic(fmt.Errorf("unsupported API version %v", c.cfg.Kubernetes.APIVersion))
- }
-
- if c.cfg.Kubernetes.IngressVersion == config.IngressNetworkingV1 {
- ingressInformer = kubeFactory.Networking().V1().Ingresses().Informer()
- } else if c.cfg.Kubernetes.IngressVersion == config.IngressNetworkingV1beta1 {
- ingressInformer = kubeFactory.Networking().V1beta1().Ingresses().Informer()
- } else {
- ingressInformer = kubeFactory.Extensions().V1beta1().Ingresses().Informer()
- }
-
- switch c.cfg.Kubernetes.ApisixRouteVersion {
- case config.ApisixV2beta2:
- apisixRouteInformer = apisixFactory.Apisix().V2beta2().ApisixRoutes().Informer()
- case config.ApisixV2beta3:
- apisixRouteInformer = apisixFactory.Apisix().V2beta3().ApisixRoutes().Informer()
- case config.ApisixV2:
- apisixRouteInformer = apisixFactory.Apisix().V2().ApisixRoutes().Informer()
- default:
- panic(fmt.Errorf("unsupported ApisixRoute version %s", c.cfg.Kubernetes.ApisixRouteVersion))
- }
-
- c.podInformer = kubeFactory.Core().V1().Pods().Informer()
- c.svcInformer = kubeFactory.Core().V1().Services().Informer()
- c.ingressInformer = ingressInformer
- c.apisixRouteInformer = apisixRouteInformer
- c.apisixUpstreamInformer = apisixUpstreamInformer
- c.apisixClusterConfigInformer = apisixClusterConfigInformer
- c.secretInformer = kubeFactory.Core().V1().Secrets().Informer()
- c.apisixTlsInformer = apisixTlsInformer
- c.apisixConsumerInformer = apisixConsumerInformer
- c.apisixPluginConfigInformer = apisixPluginConfigInformer
-
- if c.cfg.Kubernetes.WatchEndpointSlices {
- c.endpointSliceController = c.newEndpointSliceController()
- } else {
- c.endpointsController = c.newEndpointsController()
- }
- c.podController = c.newPodController()
- c.apisixUpstreamController = c.newApisixUpstreamController()
- c.ingressController = c.newIngressController()
- c.apisixRouteController = c.newApisixRouteController()
- c.apisixClusterConfigController = c.newApisixClusterConfigController()
- c.apisixTlsController = c.newApisixTlsController()
- c.secretController = c.newSecretController()
- c.apisixConsumerController = c.newApisixConsumerController()
- c.apisixPluginConfigController = c.newApisixPluginConfigController()
-}
-
-func (c *Controller) syncManifests(ctx context.Context, added, updated, deleted *utils.Manifest) error {
- return utils.SyncManifests(ctx, c.apisix, c.cfg.APISIX.DefaultClusterName, added, updated, deleted)
-}
-
-// recorderEvent recorder events for resources
-func (c *Controller) recorderEvent(object runtime.Object, eventtype, reason string, err error) {
- if err != nil {
- message := fmt.Sprintf(_messageResourceFailed, _component, err.Error())
- c.recorder.Event(object, eventtype, reason, message)
- } else {
- message := fmt.Sprintf(_messageResourceSynced, _component)
- c.recorder.Event(object, eventtype, reason, message)
- }
-}
-
-// recorderEvent recorder events for resources
-func (c *Controller) recorderEventS(object runtime.Object, eventtype, reason string, msg string) {
- c.recorder.Event(object, eventtype, reason, msg)
-}
-
-// Eventf implements the resourcelock.EventRecorder interface.
-func (c *Controller) Eventf(_ runtime.Object, eventType string, reason string, message string, _ ...interface{}) {
- log.Infow(reason, zap.String("message", message), zap.String("event_type", eventType))
-}
-
-// Run launches the controller.
-func (c *Controller) Run(stop chan struct{}) error {
- rootCtx, rootCancel := context.WithCancel(context.Background())
- defer rootCancel()
- go func() {
- <-stop
- rootCancel()
- }()
- c.MetricsCollector.ResetLeader(false)
-
- go func() {
- if err := c.apiServer.Run(rootCtx.Done()); err != nil {
- log.Errorf("failed to launch API Server: %s", err)
- }
- }()
-
- lock := &resourcelock.LeaseLock{
- LeaseMeta: metav1.ObjectMeta{
- Namespace: c.namespace,
- Name: c.cfg.Kubernetes.ElectionID,
- },
- Client: c.kubeClient.Client.CoordinationV1(),
- LockConfig: resourcelock.ResourceLockConfig{
- Identity: c.name,
- EventRecorder: c,
- },
- }
- cfg := leaderelection.LeaderElectionConfig{
- Lock: lock,
- LeaseDuration: 15 * time.Second,
- RenewDeadline: 5 * time.Second,
- RetryPeriod: 2 * time.Second,
- Callbacks: leaderelection.LeaderCallbacks{
- OnStartedLeading: c.run,
- OnNewLeader: func(identity string) {
- log.Warnf("found a new leader %s", identity)
- if identity != c.name {
- log.Infow("controller now is running as a candidate",
- zap.String("namespace", c.namespace),
- zap.String("pod", c.name),
- )
- c.MetricsCollector.ResetLeader(false)
- // delete the old APISIX cluster, so that the cached state
- // like synchronization won't be used next time the candidate
- // becomes the leader again.
- c.apisix.DeleteCluster(c.cfg.APISIX.DefaultClusterName)
- }
- },
- OnStoppedLeading: func() {
- log.Infow("controller now is running as a candidate",
- zap.String("namespace", c.namespace),
- zap.String("pod", c.name),
- )
- c.MetricsCollector.ResetLeader(false)
- // delete the old APISIX cluster, so that the cached state
- // like synchronization won't be used next time the candidate
- // becomes the leader again.
- c.apisix.DeleteCluster(c.cfg.APISIX.DefaultClusterName)
- },
- },
- ReleaseOnCancel: true,
- Name: "ingress-apisix",
- }
- elector, err := leaderelection.NewLeaderElector(cfg)
- if err != nil {
- log.Errorf("failed to create leader elector: %s", err.Error())
- return err
- }
-
-election:
- curCtx, cancel := context.WithCancel(rootCtx)
- c.leaderContextCancelFunc = cancel
- elector.Run(curCtx)
- select {
- case <-rootCtx.Done():
- return nil
- default:
- goto election
- }
-}
-
-func (c *Controller) run(ctx context.Context) {
- log.Infow("controller tries to leading ...",
- zap.String("namespace", c.namespace),
- zap.String("pod", c.name),
- )
-
- var cancelFunc context.CancelFunc
- ctx, cancelFunc = context.WithCancel(ctx)
- defer cancelFunc()
-
- // give up leader
- defer c.leaderContextCancelFunc()
-
- clusterOpts := &apisix.ClusterOptions{
- Name: c.cfg.APISIX.DefaultClusterName,
- AdminKey: c.cfg.APISIX.DefaultClusterAdminKey,
- BaseURL: c.cfg.APISIX.DefaultClusterBaseURL,
- MetricsCollector: c.MetricsCollector,
- }
- err := c.apisix.AddCluster(ctx, clusterOpts)
- if err != nil && err != apisix.ErrDuplicatedCluster {
- // TODO give up the leader role
- log.Errorf("failed to add default cluster: %s", err)
- return
- }
-
- if err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).HasSynced(ctx); err != nil {
- // TODO give up the leader role
- log.Errorf("failed to wait the default cluster to be ready: %s", err)
-
- // re-create apisix cluster, used in next c.run
- if err = c.apisix.UpdateCluster(ctx, clusterOpts); err != nil {
- log.Errorf("failed to update default cluster: %s", err)
- return
- }
- return
- }
-
- c.initWhenStartLeading()
-
- c.namespaceProvider, err = namespace.NewWatchingProvider(ctx, c.kubeClient, c.cfg)
- if err != nil {
- ctx.Done()
- return
- }
-
- c.gatewayProvider, err = gateway.NewGatewayProvider(&gateway.ProviderOptions{
- Cfg: c.cfg,
- APISIX: c.apisix,
- APISIXClusterName: c.cfg.APISIX.DefaultClusterName,
- KubeTranslator: c.translator,
- RestConfig: nil,
- KubeClient: c.kubeClient.Client,
- MetricsCollector: c.MetricsCollector,
- NamespaceProvider: c.namespaceProvider,
- })
- if err != nil {
- ctx.Done()
- return
- }
-
- // compare resources of k8s with objects of APISIX
- if err = c.CompareResources(ctx); err != nil {
- ctx.Done()
- return
- }
-
- e := utils.ParallelExecutor{}
-
- e.Add(func() {
- c.checkClusterHealth(ctx, cancelFunc)
- })
- e.Add(func() {
- c.podInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.epInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.svcInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.ingressInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.apisixRouteInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.apisixUpstreamInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.apisixClusterConfigInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.secretInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.apisixTlsInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.apisixConsumerInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.apisixPluginConfigInformer.Run(ctx.Done())
- })
- e.Add(func() {
- c.podController.run(ctx)
- })
- e.Add(func() {
- if c.cfg.Kubernetes.WatchEndpointSlices {
- c.endpointSliceController.run(ctx)
- } else {
- c.endpointsController.run(ctx)
- }
- })
-
- e.Add(func() {
- c.namespaceProvider.Run(ctx)
- })
-
- if c.cfg.Kubernetes.EnableGatewayAPI {
- e.Add(func() {
- c.gatewayProvider.Run(ctx)
- })
- }
-
- e.Add(func() {
- c.apisixUpstreamController.run(ctx)
- })
- e.Add(func() {
- c.ingressController.run(ctx)
- })
- e.Add(func() {
- c.apisixRouteController.run(ctx)
- })
- e.Add(func() {
- c.apisixClusterConfigController.run(ctx)
- })
- e.Add(func() {
- c.apisixTlsController.run(ctx)
- })
- e.Add(func() {
- c.secretController.run(ctx)
- })
- e.Add(func() {
- c.apisixConsumerController.run(ctx)
- })
- e.Add(func() {
- c.apisixPluginConfigController.run(ctx)
- })
-
- e.Add(func() {
- c.resourceSyncLoop(ctx, c.cfg.ApisixResourceSyncInterval.Duration)
- })
- c.MetricsCollector.ResetLeader(true)
-
- log.Infow("controller now is running as leader",
- zap.String("namespace", c.namespace),
- zap.String("pod", c.name),
- )
-
- <-ctx.Done()
- e.Wait()
-
- for _, execErr := range e.Errors() {
- log.Error(execErr.Error())
- }
- if len(e.Errors()) > 0 {
- log.Error("Start failed, abort...")
- cancelFunc()
- }
-}
-
-// isWatchingNamespace accepts a resource key, getting the namespace part
-// and checking whether the namespace is being watched.
-func (c *Controller) isWatchingNamespace(key string) (ok bool) {
- return c.namespaceProvider.IsWatchingNamespace(key)
-}
-
-func (c *Controller) syncSSL(ctx context.Context, ssl *apisixv1.Ssl, event types.EventType) error {
- var (
- err error
- )
- clusterName := c.cfg.APISIX.DefaultClusterName
- if event == types.EventDelete {
- err = c.apisix.Cluster(clusterName).SSL().Delete(ctx, ssl)
- } else if event == types.EventUpdate {
- _, err = c.apisix.Cluster(clusterName).SSL().Update(ctx, ssl)
- } else {
- _, err = c.apisix.Cluster(clusterName).SSL().Create(ctx, ssl)
- }
- return err
-}
-
-func (c *Controller) syncConsumer(ctx context.Context, consumer *apisixv1.Consumer, event types.EventType) (err error) {
- clusterName := c.cfg.APISIX.DefaultClusterName
- if event == types.EventDelete {
- err = c.apisix.Cluster(clusterName).Consumer().Delete(ctx, consumer)
- } else if event == types.EventUpdate {
- _, err = c.apisix.Cluster(clusterName).Consumer().Update(ctx, consumer)
- } else {
- _, err = c.apisix.Cluster(clusterName).Consumer().Create(ctx, consumer)
- }
- return
-}
-
-func (c *Controller) syncEndpoint(ctx context.Context, ep kube.Endpoint) error {
- namespace, err := ep.Namespace()
- if err != nil {
- return err
- }
- svcName := ep.ServiceName()
- svc, err := c.svcLister.Services(namespace).Get(svcName)
- if err != nil {
- if k8serrors.IsNotFound(err) {
- log.Infof("service %s/%s not found", namespace, svcName)
- return nil
- }
- log.Errorf("failed to get service %s/%s: %s", namespace, svcName, err)
- return err
- }
-
- switch c.cfg.Kubernetes.APIVersion {
- case config.ApisixV2beta3:
- var subsets []configv2beta3.ApisixUpstreamSubset
- subsets = append(subsets, configv2beta3.ApisixUpstreamSubset{})
- auKube, err := c.apisixUpstreamLister.V2beta3(namespace, svcName)
- if err != nil {
- if !k8serrors.IsNotFound(err) {
- log.Errorf("failed to get ApisixUpstream %s/%s: %s", namespace, svcName, err)
- return err
- }
- } else if auKube.V2beta3().Spec != nil && len(auKube.V2beta3().Spec.Subsets) > 0 {
- subsets = append(subsets, auKube.V2beta3().Spec.Subsets...)
- }
- clusters := c.apisix.ListClusters()
- for _, port := range svc.Spec.Ports {
- for _, subset := range subsets {
- nodes, err := c.translator.TranslateUpstreamNodes(ep, port.Port, subset.Labels)
- if err != nil {
- log.Errorw("failed to translate upstream nodes",
- zap.Error(err),
- zap.Any("endpoints", ep),
- zap.Int32("port", port.Port),
- )
- }
- name := apisixv1.ComposeUpstreamName(namespace, svcName, subset.Name, port.Port)
- for _, cluster := range clusters {
- if err := c.syncUpstreamNodesChangeToCluster(ctx, cluster, nodes, name); err != nil {
- return err
- }
- }
- }
- }
- case config.ApisixV2:
- var subsets []configv2.ApisixUpstreamSubset
- subsets = append(subsets, configv2.ApisixUpstreamSubset{})
- auKube, err := c.apisixUpstreamLister.V2beta3(namespace, svcName)
- if err != nil {
- if !k8serrors.IsNotFound(err) {
- log.Errorf("failed to get ApisixUpstream %s/%s: %s", namespace, svcName, err)
- return err
- }
- } else if auKube.V2().Spec != nil && len(auKube.V2().Spec.Subsets) > 0 {
- subsets = append(subsets, auKube.V2().Spec.Subsets...)
- }
- clusters := c.apisix.ListClusters()
- for _, port := range svc.Spec.Ports {
- for _, subset := range subsets {
- nodes, err := c.translator.TranslateUpstreamNodes(ep, port.Port, subset.Labels)
- if err != nil {
- log.Errorw("failed to translate upstream nodes",
- zap.Error(err),
- zap.Any("endpoints", ep),
- zap.Int32("port", port.Port),
- )
- }
- name := apisixv1.ComposeUpstreamName(namespace, svcName, subset.Name, port.Port)
- for _, cluster := range clusters {
- if err := c.syncUpstreamNodesChangeToCluster(ctx, cluster, nodes, name); err != nil {
- return err
- }
- }
- }
- }
- default:
- panic(fmt.Errorf("unsupported ApisixUpstream version %v", c.cfg.Kubernetes.APIVersion))
- }
- return nil
-}
-
-func (c *Controller) syncUpstreamNodesChangeToCluster(ctx context.Context, cluster apisix.Cluster, nodes apisixv1.UpstreamNodes, upsName string) error {
- upstream, err := cluster.Upstream().Get(ctx, upsName)
- if err != nil {
- if err == apisixcache.ErrNotFound {
- log.Warnw("upstream is not referenced",
- zap.String("cluster", cluster.String()),
- zap.String("upstream", upsName),
- )
- return nil
- } else {
- log.Errorw("failed to get upstream",
- zap.String("upstream", upsName),
- zap.String("cluster", cluster.String()),
- zap.Error(err),
- )
- return err
- }
- }
-
- upstream.Nodes = nodes
-
- log.Debugw("upstream binds new nodes",
- zap.Any("upstream", upstream),
- zap.String("cluster", cluster.String()),
- )
-
- updated := &utils.Manifest{
- Upstreams: []*apisixv1.Upstream{upstream},
- }
- return c.syncManifests(ctx, nil, updated, nil)
-}
-
-func (c *Controller) checkClusterHealth(ctx context.Context, cancelFunc context.CancelFunc) {
- defer cancelFunc()
- t := time.NewTicker(5 * time.Second)
- defer t.Stop()
- for {
- select {
- case <-ctx.Done():
- return
- case <-t.C:
- }
-
- err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).HealthCheck(ctx)
- if err != nil {
- // Finally failed health check, then give up leader.
- log.Warnf("failed to check health for default cluster: %s, give up leader", err)
- c.apiServer.HealthState.Lock()
- defer c.apiServer.HealthState.Unlock()
-
- c.apiServer.HealthState.Err = err
- return
- }
- log.Debugf("success check health for default cluster")
- c.MetricsCollector.IncrCheckClusterHealth(c.name)
- }
-}
-
-func (c *Controller) syncAllResources() {
- wg := sync.WaitGroup{}
- goAttach := func(handler func()) {
- wg.Add(1)
- go func() {
- defer wg.Done()
- handler()
- }()
- }
- goAttach(func() {
- c.apisixConsumerController.ResourceSync()
- })
- goAttach(func() {
- c.apisixRouteController.ResourceSync()
- })
- goAttach(func() {
- c.apisixClusterConfigController.ResourceSync()
- })
- goAttach(func() {
- c.apisixPluginConfigController.ResourceSync()
- })
- goAttach(func() {
- c.apisixUpstreamController.ResourceSync()
- })
- goAttach(func() {
- c.apisixTlsController.ResourceSync()
- })
- goAttach(func() {
- c.ingressController.ResourceSync()
- })
- wg.Wait()
-}
-
-func (c *Controller) resourceSyncLoop(ctx context.Context, interval time.Duration) {
- // The interval shall not be less than 60 seconds.
- if interval < _mininumApisixResourceSyncInterval {
- log.Warnw("The apisix-resource-sync-interval shall not be less than 60 seconds.",
- zap.String("apisix-resource-sync-interval", interval.String()),
- )
- interval = _mininumApisixResourceSyncInterval
- }
- ticker := time.NewTicker(interval)
- defer ticker.Stop()
- for {
- select {
- case <-ticker.C:
- c.syncAllResources()
- continue
- case <-ctx.Done():
- return
- }
- }
-}
diff --git a/pkg/ingress/status.go b/pkg/ingress/status.go
deleted file mode 100644
index 9042a66c..00000000
--- a/pkg/ingress/status.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package ingress
-
-import (
- "context"
-
- "go.uber.org/zap"
- apiv1 "k8s.io/api/core/v1"
- extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
- networkingv1 "k8s.io/api/networking/v1"
- networkingv1beta1 "k8s.io/api/networking/v1beta1"
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
-
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
- configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
- configv2beta2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta2"
- configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
- "github.com/apache/apisix-ingress-controller/pkg/log"
-)
-
-const (
- _conditionType = "ResourcesAvailable"
- _commonSuccessMessage = "Sync Successfully"
-)
-
-// verifyGeneration verify generation to decide whether to update status
-func (c *Controller) verifyGeneration(conditions *[]metav1.Condition, newCondition metav1.Condition) bool {
- existingCondition := meta.FindStatusCondition(*conditions, newCondition.Type)
- if existingCondition != nil && existingCondition.ObservedGeneration >= newCondition.ObservedGeneration {
- return false
- }
- return true
-}
-
-// recordStatus record resources status
-func (c *Controller) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
- // build condition
- message := _commonSuccessMessage
- if err != nil {
- message = err.Error()
- }
- condition := metav1.Condition{
- Type: _conditionType,
- Reason: reason,
- Status: status,
- Message: message,
- ObservedGeneration: generation,
- }
- client := c.kubeClient.APISIXClient
- kubeClient := c.kubeClient.Client
-
- if kubeObj, ok := at.(runtime.Object); ok {
- at = kubeObj.DeepCopyObject()
- }
-
- switch v := at.(type) {
- case *configv2beta3.ApisixTls:
- // 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.ApisixV2beta3().ApisixTlses(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixTls",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2.ApisixTls:
- // 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().ApisixTlses(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixTls",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2beta3.ApisixUpstream:
- // 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.ApisixV2beta3().ApisixUpstreams(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixUpstream",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
-
- case *configv2.ApisixUpstream:
- // 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().ApisixUpstreams(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixUpstream",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2.ApisixRoute:
- // 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().ApisixRoutes(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixRoute",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2beta2.ApisixRoute:
- // 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.ApisixV2beta2().ApisixRoutes(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixRoute",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2beta3.ApisixRoute:
- // 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.ApisixV2beta3().ApisixRoutes(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixRoute",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2beta3.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.ApisixV2beta3().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 *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 {
- 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.ApisixV2beta3().ApisixPluginConfigs(v.Namespace).
- UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for ApisixPluginConfig",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- }
- case *configv2beta3.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.ApisixV2beta3().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 *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()
- if err != nil {
- log.Errorw("failed to get APISIX gateway external IPs",
- zap.Error(err),
- )
-
- }
-
- v.ObjectMeta.Generation = generation
- v.Status.LoadBalancer.Ingress = lbips
- if _, errRecord := kubeClient.NetworkingV1().Ingresses(v.Namespace).UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for IngressV1",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
-
- case *networkingv1beta1.Ingress:
- // set to status
- lbips, err := c.ingressLBStatusIPs()
- if err != nil {
- log.Errorw("failed to get APISIX gateway external IPs",
- zap.Error(err),
- )
-
- }
-
- v.ObjectMeta.Generation = generation
- v.Status.LoadBalancer.Ingress = lbips
- if _, errRecord := kubeClient.NetworkingV1beta1().Ingresses(v.Namespace).UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for IngressV1",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- case *extensionsv1beta1.Ingress:
- // set to status
- lbips, err := c.ingressLBStatusIPs()
- if err != nil {
- log.Errorw("failed to get APISIX gateway external IPs",
- zap.Error(err),
- )
-
- }
-
- v.ObjectMeta.Generation = generation
- v.Status.LoadBalancer.Ingress = lbips
- if _, errRecord := kubeClient.ExtensionsV1beta1().Ingresses(v.Namespace).UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
- log.Errorw("failed to record status change for IngressV1",
- zap.Error(errRecord),
- zap.String("name", v.Name),
- zap.String("namespace", v.Namespace),
- )
- }
- default:
- // This should not be executed
- log.Errorf("unsupported resource record: %s", v)
- }
-}
-
-// ingressLBStatusIPs organizes the available addresses
-func (c *Controller) ingressLBStatusIPs() ([]apiv1.LoadBalancerIngress, error) {
- return utils.IngressLBStatusIPs(c.cfg.IngressPublishService, c.cfg.IngressStatusAddress, c.kubeClient.Client)
-}
diff --git a/pkg/kube/translation/ingress_test.go b/pkg/kube/translation/ingress_test.go
deleted file mode 100644
index ab81b966..00000000
--- a/pkg/kube/translation/ingress_test.go
+++ /dev/null
@@ -1,1376 +0,0 @@
-// 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 translation
-
-import (
- "context"
- "path"
- "testing"
-
- "github.com/stretchr/testify/assert"
- corev1 "k8s.io/api/core/v1"
- extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
- networkingv1 "k8s.io/api/networking/v1"
- networkingv1beta1 "k8s.io/api/networking/v1beta1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/client-go/informers"
- "k8s.io/client-go/kubernetes/fake"
- "k8s.io/client-go/tools/cache"
-
- "github.com/apache/apisix-ingress-controller/pkg/config"
- "github.com/apache/apisix-ingress-controller/pkg/id"
- "github.com/apache/apisix-ingress-controller/pkg/kube"
- configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
- fakeapisix "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/fake"
- apisixinformers "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions"
- apisixconst "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/const"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation/annotations"
- apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
- v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
-)
-
-var (
- _testSvc = &corev1.Service{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-service",
- Namespace: "default",
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
- {
- Name: "port1",
- Port: 80,
- TargetPort: intstr.IntOrString{
- Type: intstr.Int,
- IntVal: 9080,
- },
- },
- {
- Name: "port2",
- Port: 443,
- TargetPort: intstr.IntOrString{
- Type: intstr.Int,
- IntVal: 9443,
- },
- },
- },
- },
- }
- _testEp = &corev1.Endpoints{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-service",
- Namespace: "default",
- },
- Subsets: []corev1.EndpointSubset{
- {
- Ports: []corev1.EndpointPort{
- {
- Name: "port1",
- Port: 9080,
- },
- {
- Name: "port2",
- Port: 9443,
- },
- },
- Addresses: []corev1.EndpointAddress{
- {IP: "192.168.1.1"},
- {IP: "192.168.1.2"},
- },
- },
- },
- }
-)
-
-func TestTranslateIngressV1NoBackend(t *testing.T) {
- prefix := networkingv1.PathTypePrefix
- // no backend.
- ing := &networkingv1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- },
- Spec: networkingv1.IngressSpec{
- Rules: []networkingv1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1.IngressRuleValue{
- HTTP: &networkingv1.HTTPIngressRuleValue{
- Paths: []networkingv1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- },
- },
- },
- },
- },
- },
- },
- }
- tr := &translator{}
- ctx, err := tr.translateIngressV1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 0)
- assert.Len(t, ctx.PluginConfigs, 0)
- assert.Equal(t, "", ctx.Routes[0].UpstreamId)
- assert.Equal(t, "", ctx.Routes[0].PluginConfigId)
- assert.Equal(t, []string{"/foo", "/foo/*"}, ctx.Routes[0].Uris)
-}
-
-func TestTranslateIngressV1BackendWithInvalidService(t *testing.T) {
- prefix := networkingv1.PathTypePrefix
- // no backend.
- ing := &networkingv1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- },
- Spec: networkingv1.IngressSpec{
- Rules: []networkingv1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1.IngressRuleValue{
- HTTP: &networkingv1.HTTPIngressRuleValue{
- Paths: []networkingv1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- Backend: networkingv1.IngressBackend{
- Service: &networkingv1.IngressServiceBackend{
- Name: "test-service",
- Port: networkingv1.ServiceBackendPort{
- Name: "undefined-port",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- },
- }
- ctx, err := tr.translateIngressV1(ing, false)
- assert.NotNil(t, err)
- assert.Nil(t, ctx)
- assert.Equal(t, "service \"test-service\" not found", err.Error())
-
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err = client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- <-processCh
- ctx, err = tr.translateIngressV1(ing, false)
- assert.Nil(t, ctx, nil)
- assert.Equal(t, &translateError{
- field: "service",
- reason: "port not found",
- }, err)
-}
-
-func TestTranslateIngressV1WithRegex(t *testing.T) {
- testTranslateIngressV1WithRegexReferenceUpstreamVersion(t, config.ApisixV2)
- testTranslateIngressV1WithRegexReferenceUpstreamVersion(t, config.ApisixV2beta3)
-}
-
-func testTranslateIngressV1WithRegexReferenceUpstreamVersion(t *testing.T, apiVersion string) func(t *testing.T) {
- return func(t *testing.T) {
- prefix := networkingv1.PathTypeImplementationSpecific
- regexPath := "/foo/*/bar"
- ing := &networkingv1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/use-regex": "true",
- },
- },
- Spec: networkingv1.IngressSpec{
- Rules: []networkingv1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1.IngressRuleValue{
- HTTP: &networkingv1.HTTPIngressRuleValue{
- Paths: []networkingv1.HTTPIngressPath{
- {
- Path: regexPath,
- PathType: &prefix,
- Backend: networkingv1.IngressBackend{
- Service: &networkingv1.IngressServiceBackend{
- Name: "test-service",
- Port: networkingv1.ServiceBackendPort{
- Name: "port1",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: apiVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressV1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 1)
- // the number of the PluginConfigs should be zero, cause there no available Annotations matched te rule
- assert.Len(t, ctx.PluginConfigs, 0)
- routeVars, err := tr.translateRouteMatchExprs([]configv2.ApisixRouteHTTPMatchExpr{{
- Subject: configv2.ApisixRouteHTTPMatchExprSubject{
- Scope: apisixconst.ScopePath,
- },
- Op: apisixconst.OpRegexMatch,
- Value: ®exPath,
- }})
- assert.Nil(t, err)
-
- var expectedVars v1.Vars = routeVars
-
- assert.Equal(t, []string{"/*"}, ctx.Routes[0].Uris)
- assert.Equal(t, expectedVars, ctx.Routes[0].Vars)
- }
-}
-
-func TestTranslateIngressV1(t *testing.T) {
- testTranslateIngressV1ReferenceUpstreamVersion(t, config.ApisixV2beta3)
- testTranslateIngressV1ReferenceUpstreamVersion(t, config.ApisixV2)
-}
-
-func testTranslateIngressV1ReferenceUpstreamVersion(t *testing.T, apiVersoin string) func(*testing.T) {
- return func(*testing.T) {
- prefix := networkingv1.PathTypePrefix
- // no backend.
- ing := &networkingv1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/use-regex": "true",
- path.Join(annotations.AnnotationsPrefix, "enable-cors"): "true",
- path.Join(annotations.AnnotationsPrefix, "allowlist-source-range"): "127.0.0.1",
- path.Join(annotations.AnnotationsPrefix, "plugin-config-name"): "echo-and-cors-apc",
- },
- },
- Spec: networkingv1.IngressSpec{
- Rules: []networkingv1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1.IngressRuleValue{
- HTTP: &networkingv1.HTTPIngressRuleValue{
- Paths: []networkingv1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- Backend: networkingv1.IngressBackend{
- Service: &networkingv1.IngressServiceBackend{
- Name: "test-service",
- Port: networkingv1.ServiceBackendPort{
- Name: "port1",
- },
- },
- },
- },
- {
- Path: "/bar",
- Backend: networkingv1.IngressBackend{
- Service: &networkingv1.IngressServiceBackend{
- Name: "test-service",
- Port: networkingv1.ServiceBackendPort{
- Number: 443,
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: apiVersoin,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressV1(ing, false)
- annoExtractor := annotations.NewExtractor(ing.Annotations)
- pluginConfigName := annoExtractor.GetStringAnnotation(path.Join(annotations.AnnotationsPrefix, "plugin-config-name"))
-
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 2)
- assert.Len(t, ctx.Upstreams, 2)
-
- assert.Equal(t, []string{"/foo", "/foo/*"}, ctx.Routes[0].Uris)
- assert.Equal(t, ctx.Upstreams[0].ID, ctx.Routes[0].UpstreamId)
- assert.Equal(t, "apisix.apache.org", ctx.Routes[0].Host)
- assert.Len(t, ctx.Routes[0].Plugins, 2)
- assert.Equal(t, ctx.Routes[0].PluginConfigId, id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)))
- assert.Equal(t, []string{"/bar"}, ctx.Routes[1].Uris)
- assert.Equal(t, ctx.Upstreams[1].ID, ctx.Routes[1].UpstreamId)
- assert.Equal(t, "apisix.apache.org", ctx.Routes[1].Host)
- assert.Len(t, ctx.Routes[1].Plugins, 2)
- assert.Equal(t, ctx.Routes[1].PluginConfigId, id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)))
-
- assert.Equal(t, "roundrobin", ctx.Upstreams[0].Type)
- assert.Equal(t, "http", ctx.Upstreams[0].Scheme)
- assert.Len(t, ctx.Upstreams[0].Nodes, 2)
- assert.Equal(t, 9080, ctx.Upstreams[0].Nodes[0].Port)
- assert.Equal(t, "192.168.1.1", ctx.Upstreams[0].Nodes[0].Host)
- assert.Equal(t, 9080, ctx.Upstreams[0].Nodes[1].Port)
- assert.Equal(t, "192.168.1.2", ctx.Upstreams[0].Nodes[1].Host)
-
- assert.Equal(t, "roundrobin", ctx.Upstreams[1].Type)
- assert.Equal(t, "http", ctx.Upstreams[1].Scheme)
- assert.Len(t, ctx.Upstreams[1].Nodes, 2)
- assert.Equal(t, 9443, ctx.Upstreams[1].Nodes[0].Port)
- assert.Equal(t, "192.168.1.1", ctx.Upstreams[1].Nodes[0].Host)
- assert.Equal(t, 9443, ctx.Upstreams[1].Nodes[1].Port)
- assert.Equal(t, "192.168.1.2", ctx.Upstreams[1].Nodes[1].Host)
- }
-}
-
-func TestTranslateIngressV1beta1NoBackend(t *testing.T) {
- prefix := networkingv1beta1.PathTypePrefix
- // no backend.
- ing := &networkingv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- },
- Spec: networkingv1beta1.IngressSpec{
- Rules: []networkingv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1beta1.IngressRuleValue{
- HTTP: &networkingv1beta1.HTTPIngressRuleValue{
- Paths: []networkingv1beta1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- },
- },
- },
- },
- },
- },
- },
- }
- tr := &translator{}
- ctx, err := tr.translateIngressV1beta1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 0)
- assert.Len(t, ctx.PluginConfigs, 0)
- assert.Equal(t, "", ctx.Routes[0].UpstreamId)
- assert.Equal(t, "", ctx.Routes[0].PluginConfigId)
- assert.Equal(t, []string{"/foo", "/foo/*"}, ctx.Routes[0].Uris)
-}
-
-func TestTranslateIngressV1beta1BackendWithInvalidService(t *testing.T) {
- prefix := networkingv1beta1.PathTypePrefix
- // no backend.
- ing := &networkingv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- },
- Spec: networkingv1beta1.IngressSpec{
- Rules: []networkingv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1beta1.IngressRuleValue{
- HTTP: &networkingv1beta1.HTTPIngressRuleValue{
- Paths: []networkingv1beta1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- Backend: networkingv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "undefined-port",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- },
- }
- ctx, err := tr.translateIngressV1beta1(ing, false)
- assert.NotNil(t, err)
- assert.Nil(t, ctx)
- assert.Equal(t, "service \"test-service\" not found", err.Error())
-
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err = client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- <-processCh
- ctx, err = tr.translateIngressV1beta1(ing, false)
- assert.Nil(t, ctx)
- assert.Equal(t, &translateError{
- field: "service",
- reason: "port not found",
- }, err)
-}
-
-func TestTranslateIngressV1beta1WithRegex(t *testing.T) {
- prefix := networkingv1beta1.PathTypeImplementationSpecific
- // no backend.
- regexPath := "/foo/*/bar"
- ing := &networkingv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/use-regex": "true",
- },
- },
- Spec: networkingv1beta1.IngressSpec{
- Rules: []networkingv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1beta1.IngressRuleValue{
- HTTP: &networkingv1beta1.HTTPIngressRuleValue{
- Paths: []networkingv1beta1.HTTPIngressPath{
- {
- Path: regexPath,
- PathType: &prefix,
- Backend: networkingv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "port1",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressV1beta1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 1)
- // the number of the PluginConfigs should be zero, cause there no available Annotations matched te rule
- assert.Len(t, ctx.PluginConfigs, 0)
-
- routeVars, err := tr.translateRouteMatchExprs([]configv2.ApisixRouteHTTPMatchExpr{{
- Subject: configv2.ApisixRouteHTTPMatchExprSubject{
- Scope: apisixconst.ScopePath,
- },
- Op: apisixconst.OpRegexMatch,
- Value: ®exPath,
- }})
- assert.Nil(t, err)
- var expectedVars v1.Vars = routeVars
- assert.Equal(t, []string{"/*"}, ctx.Routes[0].Uris)
- assert.Equal(t, expectedVars, ctx.Routes[0].Vars)
-}
-
-func TestTranslateIngressV1beta1(t *testing.T) {
- prefix := networkingv1beta1.PathTypePrefix
- // no backend.
- ing := &networkingv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/use-regex": "true",
- path.Join(annotations.AnnotationsPrefix, "enable-cors"): "true",
- path.Join(annotations.AnnotationsPrefix, "allowlist-source-range"): "127.0.0.1",
- path.Join(annotations.AnnotationsPrefix, "enable-cors222"): "true",
- path.Join(annotations.AnnotationsPrefix, "plugin-config-name"): "echo-and-cors-apc",
- },
- },
- Spec: networkingv1beta1.IngressSpec{
- Rules: []networkingv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1beta1.IngressRuleValue{
- HTTP: &networkingv1beta1.HTTPIngressRuleValue{
- Paths: []networkingv1beta1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- Backend: networkingv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "port1",
- },
- },
- },
- {
- Path: "/bar",
- Backend: networkingv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.Int,
- IntVal: 443,
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressV1beta1(ing, false)
- annoExtractor := annotations.NewExtractor(ing.Annotations)
- pluginConfigName := annoExtractor.GetStringAnnotation(path.Join(annotations.AnnotationsPrefix, "plugin-config-name"))
-
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 2)
- assert.Len(t, ctx.Upstreams, 2)
-
- assert.Equal(t, []string{"/foo", "/foo/*"}, ctx.Routes[0].Uris)
- assert.Equal(t, ctx.Upstreams[0].ID, ctx.Routes[0].UpstreamId)
- assert.Equal(t, "apisix.apache.org", ctx.Routes[0].Host)
- assert.Len(t, ctx.Routes[0].Plugins, 2)
- assert.Equal(t, ctx.Routes[0].PluginConfigId, id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)))
-
- assert.Equal(t, []string{"/bar"}, ctx.Routes[1].Uris)
- assert.Equal(t, ctx.Upstreams[1].ID, ctx.Routes[1].UpstreamId)
- assert.Equal(t, "apisix.apache.org", ctx.Routes[1].Host)
- assert.Len(t, ctx.Routes[1].Plugins, 2)
- assert.Equal(t, ctx.Routes[1].PluginConfigId, id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)))
-
- assert.Equal(t, "roundrobin", ctx.Upstreams[0].Type)
- assert.Equal(t, "http", ctx.Upstreams[0].Scheme)
- assert.Len(t, ctx.Upstreams[0].Nodes, 2)
- assert.Equal(t, 9080, ctx.Upstreams[0].Nodes[0].Port)
- assert.Equal(t, "192.168.1.1", ctx.Upstreams[0].Nodes[0].Host)
- assert.Equal(t, 9080, ctx.Upstreams[0].Nodes[1].Port)
- assert.Equal(t, "192.168.1.2", ctx.Upstreams[0].Nodes[1].Host)
-
- assert.Equal(t, "roundrobin", ctx.Upstreams[1].Type)
- assert.Equal(t, "http", ctx.Upstreams[1].Scheme)
- assert.Len(t, ctx.Upstreams[1].Nodes, 2)
- assert.Equal(t, 9443, ctx.Upstreams[1].Nodes[0].Port)
- assert.Equal(t, "192.168.1.1", ctx.Upstreams[1].Nodes[0].Host)
- assert.Equal(t, 9443, ctx.Upstreams[1].Nodes[1].Port)
- assert.Equal(t, "192.168.1.2", ctx.Upstreams[1].Nodes[1].Host)
-}
-
-func TestTranslateIngressExtensionsV1beta1(t *testing.T) {
- prefix := extensionsv1beta1.PathTypePrefix
- // no backend.
- ing := &extensionsv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/use-regex": "true",
- path.Join(annotations.AnnotationsPrefix, "enable-cors"): "true",
- path.Join(annotations.AnnotationsPrefix, "allowlist-source-range"): "127.0.0.1",
- path.Join(annotations.AnnotationsPrefix, "enable-cors222"): "true",
- path.Join(annotations.AnnotationsPrefix, "plugin-config-name"): "echo-and-cors-apc",
- },
- },
- Spec: extensionsv1beta1.IngressSpec{
- Rules: []extensionsv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: extensionsv1beta1.IngressRuleValue{
- HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
- Paths: []extensionsv1beta1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- Backend: extensionsv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "port1",
- },
- },
- },
- {
- Path: "/bar",
- Backend: extensionsv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.Int,
- IntVal: 443,
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressExtensionsV1beta1(ing, false)
- annoExtractor := annotations.NewExtractor(ing.Annotations)
- pluginConfigName := annoExtractor.GetStringAnnotation(path.Join(annotations.AnnotationsPrefix, "plugin-config-name"))
-
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 2)
- assert.Len(t, ctx.Upstreams, 2)
-
- assert.Equal(t, []string{"/foo", "/foo/*"}, ctx.Routes[0].Uris)
- assert.Equal(t, ctx.Upstreams[0].ID, ctx.Routes[0].UpstreamId)
- assert.Equal(t, "apisix.apache.org", ctx.Routes[0].Host)
- assert.Len(t, ctx.Routes[0].Plugins, 2)
- assert.Equal(t, ctx.Routes[0].PluginConfigId, id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)))
-
- assert.Equal(t, []string{"/bar"}, ctx.Routes[1].Uris)
- assert.Equal(t, ctx.Upstreams[1].ID, ctx.Routes[1].UpstreamId)
- assert.Equal(t, "apisix.apache.org", ctx.Routes[1].Host)
- assert.Len(t, ctx.Routes[1].Plugins, 2)
- assert.Equal(t, ctx.Routes[1].PluginConfigId, id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)))
-
- assert.Equal(t, "roundrobin", ctx.Upstreams[0].Type)
- assert.Equal(t, "http", ctx.Upstreams[0].Scheme)
- assert.Len(t, ctx.Upstreams[0].Nodes, 2)
- assert.Equal(t, 9080, ctx.Upstreams[0].Nodes[0].Port)
- assert.Equal(t, "192.168.1.1", ctx.Upstreams[0].Nodes[0].Host)
- assert.Equal(t, 9080, ctx.Upstreams[0].Nodes[1].Port)
- assert.Equal(t, "192.168.1.2", ctx.Upstreams[0].Nodes[1].Host)
-
- assert.Equal(t, "roundrobin", ctx.Upstreams[1].Type)
- assert.Equal(t, "http", ctx.Upstreams[1].Scheme)
- assert.Len(t, ctx.Upstreams[1].Nodes, 2)
- assert.Equal(t, 9443, ctx.Upstreams[1].Nodes[0].Port)
- assert.Equal(t, "192.168.1.1", ctx.Upstreams[1].Nodes[0].Host)
- assert.Equal(t, 9443, ctx.Upstreams[1].Nodes[1].Port)
- assert.Equal(t, "192.168.1.2", ctx.Upstreams[1].Nodes[1].Host)
-}
-
-func TestTranslateIngressExtensionsV1beta1BackendWithInvalidService(t *testing.T) {
- prefix := extensionsv1beta1.PathTypePrefix
- // no backend.
- ing := &extensionsv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- },
- Spec: extensionsv1beta1.IngressSpec{
- Rules: []extensionsv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: extensionsv1beta1.IngressRuleValue{
- HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
- Paths: []extensionsv1beta1.HTTPIngressPath{
- {
- Path: "/foo",
- PathType: &prefix,
- Backend: extensionsv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "undefined-port",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- },
- }
- ctx, err := tr.translateIngressExtensionsV1beta1(ing, false)
- assert.Nil(t, ctx)
- assert.NotNil(t, err)
- assert.Equal(t, "service \"test-service\" not found", err.Error())
-
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err = client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- <-processCh
- ctx, err = tr.translateIngressExtensionsV1beta1(ing, false)
- assert.Nil(t, ctx)
- assert.Equal(t, &translateError{
- field: "service",
- reason: "port not found",
- }, err)
-}
-
-func TestTranslateIngressExtensionsV1beta1WithRegex(t *testing.T) {
- prefix := extensionsv1beta1.PathTypeImplementationSpecific
- regexPath := "/foo/*/bar"
- ing := &extensionsv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/use-regex": "true",
- },
- },
- Spec: extensionsv1beta1.IngressSpec{
- Rules: []extensionsv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: extensionsv1beta1.IngressRuleValue{
- HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
- Paths: []extensionsv1beta1.HTTPIngressPath{
- {
- Path: regexPath,
- PathType: &prefix,
- Backend: extensionsv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "port1",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressExtensionsV1beta1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 1)
- // the number of the PluginConfigs should be zero, cause there no available Annotations matched te rule
- assert.Len(t, ctx.PluginConfigs, 0)
- routeVars, err := tr.translateRouteMatchExprs([]configv2.ApisixRouteHTTPMatchExpr{{
- Subject: configv2.ApisixRouteHTTPMatchExprSubject{
- Scope: apisixconst.ScopePath,
- },
- Op: apisixconst.OpRegexMatch,
- Value: ®exPath,
- }})
- assert.Nil(t, err)
-
- var expectedVars v1.Vars = routeVars
-
- assert.Equal(t, []string{"/*"}, ctx.Routes[0].Uris)
- assert.Equal(t, expectedVars, ctx.Routes[0].Vars)
-}
-
-func TestTranslateIngressV1WithWebsocket(t *testing.T) {
- prefix := networkingv1.PathTypeImplementationSpecific
- regexPath := "/foo/*/bar"
- ing := &networkingv1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/enable-websocket": "true",
- },
- },
- Spec: networkingv1.IngressSpec{
- Rules: []networkingv1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1.IngressRuleValue{
- HTTP: &networkingv1.HTTPIngressRuleValue{
- Paths: []networkingv1.HTTPIngressPath{
- {
- Path: regexPath,
- PathType: &prefix,
- Backend: networkingv1.IngressBackend{
- Service: &networkingv1.IngressServiceBackend{
- Name: "test-service",
- Port: networkingv1.ServiceBackendPort{
- Name: "port1",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressV1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 1)
- // the number of the PluginConfigs should be zero, cause there no available Annotations matched te rule
- assert.Len(t, ctx.PluginConfigs, 0)
-
- assert.Equal(t, true, ctx.Routes[0].EnableWebsocket)
-}
-
-func TestTranslateIngressV1beta1WithWebsocket(t *testing.T) {
- prefix := networkingv1beta1.PathTypeImplementationSpecific
- // no backend.
- regexPath := "/foo/*/bar"
- ing := &networkingv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/enable-websocket": "true",
- },
- },
- Spec: networkingv1beta1.IngressSpec{
- Rules: []networkingv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: networkingv1beta1.IngressRuleValue{
- HTTP: &networkingv1beta1.HTTPIngressRuleValue{
- Paths: []networkingv1beta1.HTTPIngressPath{
- {
- Path: regexPath,
- PathType: &prefix,
- Backend: networkingv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "port1",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressV1beta1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 1)
- // the number of the PluginConfigs should be zero, cause there no available Annotations matched te rule
- assert.Len(t, ctx.PluginConfigs, 0)
-
- assert.Nil(t, err)
- assert.Equal(t, true, ctx.Routes[0].EnableWebsocket)
-}
-
-func TestTranslateIngressExtensionsV1beta1WithWebsocket(t *testing.T) {
- prefix := extensionsv1beta1.PathTypeImplementationSpecific
- regexPath := "/foo/*/bar"
- ing := &extensionsv1beta1.Ingress{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "default",
- Annotations: map[string]string{
- "k8s.apisix.apache.org/enable-websocket": "true",
- },
- },
- Spec: extensionsv1beta1.IngressSpec{
- Rules: []extensionsv1beta1.IngressRule{
- {
- Host: "apisix.apache.org",
- IngressRuleValue: extensionsv1beta1.IngressRuleValue{
- HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
- Paths: []extensionsv1beta1.HTTPIngressPath{
- {
- Path: regexPath,
- PathType: &prefix,
- Backend: extensionsv1beta1.IngressBackend{
- ServiceName: "test-service",
- ServicePort: intstr.IntOrString{
- Type: intstr.String,
- StrVal: "port1",
- },
- },
- },
- },
- },
- },
- },
- },
- },
- }
- client := fake.NewSimpleClientset()
- informersFactory := informers.NewSharedInformerFactory(client, 0)
- svcInformer := informersFactory.Core().V1().Services().Informer()
- svcLister := informersFactory.Core().V1().Services().Lister()
- epLister, epInformer := kube.NewEndpointListerAndInformer(informersFactory, false)
- apisixClient := fakeapisix.NewSimpleClientset()
- apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
- processCh := make(chan struct{})
- svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
- epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- processCh <- struct{}{}
- },
- })
-
- stopCh := make(chan struct{})
- defer close(stopCh)
- go svcInformer.Run(stopCh)
- go epInformer.Run(stopCh)
- cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
-
- _, err := client.CoreV1().Services("default").Create(context.Background(), _testSvc, metav1.CreateOptions{})
- assert.Nil(t, err)
- _, err = client.CoreV1().Endpoints("default").Create(context.Background(), _testEp, metav1.CreateOptions{})
- assert.Nil(t, err)
-
- tr := &translator{
- TranslatorOptions: &TranslatorOptions{
- ServiceLister: svcLister,
- EndpointLister: epLister,
- ApisixUpstreamLister: kube.NewApisixUpstreamLister(
- apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
- apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
- ),
- APIVersion: config.DefaultAPIVersion,
- },
- }
-
- <-processCh
- <-processCh
- ctx, err := tr.translateIngressExtensionsV1beta1(ing, false)
- assert.Nil(t, err)
- assert.Len(t, ctx.Routes, 1)
- assert.Len(t, ctx.Upstreams, 1)
- // the number of the PluginConfigs should be zero, cause there no available Annotations matched te rule
- assert.Len(t, ctx.PluginConfigs, 0)
-
- assert.Equal(t, true, ctx.Routes[0].EnableWebsocket)
-}
diff --git a/pkg/kube/translation/translator.go b/pkg/kube/translation/translator.go
deleted file mode 100644
index 28f0afe8..00000000
--- a/pkg/kube/translation/translator.go
+++ /dev/null
@@ -1,426 +0,0 @@
-// 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 translation
-
-import (
- "fmt"
-
- "go.uber.org/zap"
- corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- listerscorev1 "k8s.io/client-go/listers/core/v1"
-
- "github.com/apache/apisix-ingress-controller/pkg/apisix"
- config "github.com/apache/apisix-ingress-controller/pkg/config"
- "github.com/apache/apisix-ingress-controller/pkg/kube"
- configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
- configv2beta2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta2"
- configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
- "github.com/apache/apisix-ingress-controller/pkg/log"
- "github.com/apache/apisix-ingress-controller/pkg/types"
- apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
-)
-
-const (
- _defaultWeight = 100
-)
-
-type translateError struct {
- field string
- reason string
-}
-
-func (te *translateError) Error() string {
- return fmt.Sprintf("%s: %s", te.field, te.reason)
-}
-
-// Translator translates Apisix* CRD resources to the description in APISIX.
-type Translator interface {
- // TranslateUpstreamNodes translate Endpoints resources to APISIX Upstream nodes
- // according to the give port. Extra labels can be passed to filter the ultimate
- // upstream nodes.
- TranslateUpstreamNodes(kube.Endpoint, int32, types.Labels) (apisixv1.UpstreamNodes, error)
- // TranslateUpstreamConfigV2beta3 translates ApisixUpstreamConfig (part of ApisixUpstream)
- // to APISIX Upstream, it doesn't fill the the Upstream metadata and nodes.
- TranslateUpstreamConfigV2beta3(*configv2beta3.ApisixUpstreamConfig) (*apisixv1.Upstream, error)
- // TranslateUpstreamConfigV2 translates ApisixUpstreamConfig (part of ApisixUpstream)
- // to APISIX Upstream, it doesn't fill the the Upstream metadata and nodes.
- TranslateUpstreamConfigV2(*configv2.ApisixUpstreamConfig) (*apisixv1.Upstream, error)
- // TranslateUpstream composes an upstream according to the
- // given namespace, name (searching Service/Endpoints) and port (filtering Endpoints).
- // The returned Upstream doesn't have metadata info.
- // It doesn't assign any metadata fields, so it's caller's responsibility to decide
- // the metadata.
- // Note the subset is used to filter the ultimate node list, only pods whose labels
- // matching the subset labels (defined in ApisixUpstream) will be selected.
- // When the subset is not found, the node list will be empty. When the subset is empty,
- // all pods IP will be filled.
- TranslateUpstream(string, string, string, int32) (*apisixv1.Upstream, error)
- // TranslateIngress composes a couple of APISIX Routes and upstreams according
- // to the given Ingress resource.
- // For old objects, you cannot use TranslateIngress to build. Because it needs to parse the latest service, which will cause data inconsistency.
- TranslateIngress(kube.Ingress, ...bool) (*TranslateContext, error)
- // TranslateOldIngress get route objects from cache
- // Build upstream and plugin_config through route
- TranslateOldIngress(kube.Ingress) (*TranslateContext, error)
- // TranslateRouteV2beta2 translates the configv2beta2.ApisixRoute object into several Route,
- // and Upstream resources.
- TranslateRouteV2beta2(*configv2beta2.ApisixRoute) (*TranslateContext, error)
- // TranslateRouteV2beta2NotStrictly translates the configv2beta2.ApisixRoute object into several Route,
- // and Upstream resources not strictly, only used for delete event.
- TranslateRouteV2beta2NotStrictly(*configv2beta2.ApisixRoute) (*TranslateContext, error)
- // TranslateRouteV2beta3 translates the configv2beta3.ApisixRoute object into several Route,
- // Upstream and PluginConfig resources.
- TranslateRouteV2beta3(*configv2beta3.ApisixRoute) (*TranslateContext, error)
- // TranslateRouteV2beta3NotStrictly translates the configv2beta3.ApisixRoute object into several Route,
- // Upstream and PluginConfig resources not strictly, only used for delete event.
- TranslateRouteV2beta3NotStrictly(*configv2beta3.ApisixRoute) (*TranslateContext, error)
- // TranslateRouteV2 translates the configv2.ApisixRoute object into several Route,
- // Upstream and PluginConfig resources.
- TranslateRouteV2(*configv2.ApisixRoute) (*TranslateContext, error)
- // TranslateRouteV2NotStrictly translates the configv2.ApisixRoute object into several Route,
- // Upstream and PluginConfig resources not strictly, only used for delete event.
- TranslateRouteV2NotStrictly(*configv2.ApisixRoute) (*TranslateContext, error)
- // TranslateOldRoute get route and stream_route objects from cache
- // Build upstream and plugin_config through route and stream_route
- TranslateOldRoute(kube.ApisixRoute) (*TranslateContext, error)
- // TranslateSSLV2Beta3 translates the configv2beta3.ApisixTls object into the APISIX SSL resource.
- TranslateSSLV2Beta3(*configv2beta3.ApisixTls) (*apisixv1.Ssl, error)
- // TranslateSSLV2 translates the configv2.ApisixTls object into the APISIX SSL resource.
- TranslateSSLV2(*configv2.ApisixTls) (*apisixv1.Ssl, error)
- // TranslateClusterConfig translates the configv2beta3.ApisixClusterConfig object into the APISIX
- // Global Rule resource.
- 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.
- 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
- // resources not strictly, only used for delete event.
- TranslatePluginConfigV2beta3NotStrictly(*configv2beta3.ApisixPluginConfig) (*TranslateContext, error)
- // TranslatePluginConfigV2 translates the configv2.ApisixPluginConfig object into several PluginConfig
- // resources.
- TranslatePluginConfigV2(*configv2.ApisixPluginConfig) (*TranslateContext, error)
- // TranslatePluginConfigV2NotStrictly translates the configv2.ApisixPluginConfig object into several PluginConfig
- // resources not strictly, only used for delete event.
- TranslatePluginConfigV2NotStrictly(*configv2.ApisixPluginConfig) (*TranslateContext, error)
- // ExtractKeyPair extracts certificate and private key pair from secret
- // Supports APISIX style ("cert" and "key") and Kube style ("tls.crt" and "tls.key)
- ExtractKeyPair(s *corev1.Secret, hasPrivateKey bool) ([]byte, []byte, error)
-}
-
-// TranslatorOptions contains options to help Translator
-// work well.
-type TranslatorOptions struct {
- PodCache types.PodCache
- PodLister listerscorev1.PodLister
- EndpointLister kube.EndpointLister
- ServiceLister listerscorev1.ServiceLister
- ApisixUpstreamLister kube.ApisixUpstreamLister
- SecretLister listerscorev1.SecretLister
- UseEndpointSlices bool
- APIVersion string
- Apisix apisix.APISIX
- ClusterName string
-}
-
-type translator struct {
- *TranslatorOptions
-}
-
-// NewTranslator initializes a APISIX CRD resources Translator.
-func NewTranslator(opts *TranslatorOptions) Translator {
- return &translator{
- TranslatorOptions: opts,
- }
-}
-
-func (t *translator) TranslateUpstreamConfigV2beta3(au *configv2beta3.ApisixUpstreamConfig) (*apisixv1.Upstream, error) {
- ups := apisixv1.NewDefaultUpstream()
- if err := t.translateUpstreamScheme(au.Scheme, ups); err != nil {
- return nil, err
- }
- if err := t.translateUpstreamLoadBalancerV2beta3(au.LoadBalancer, ups); err != nil {
- return nil, err
- }
- if err := t.translateUpstreamHealthCheckV2beta3(au.HealthCheck, ups); err != nil {
- return nil, err
- }
- if err := t.translateUpstreamRetriesAndTimeoutV2beta3(au.Retries, au.Timeout, ups); err != nil {
- return nil, err
- }
- if err := t.translateClientTLSV2beta3(au.TLSSecret, ups); err != nil {
- return nil, err
- }
- return ups, nil
-}
-
-func (t *translator) TranslateUpstreamConfigV2(au *configv2.ApisixUpstreamConfig) (*apisixv1.Upstream, error) {
- ups := apisixv1.NewDefaultUpstream()
- if err := t.translateUpstreamScheme(au.Scheme, ups); err != nil {
- return nil, err
- }
- if err := t.translateUpstreamLoadBalancerV2(au.LoadBalancer, ups); err != nil {
- return nil, err
- }
- if err := t.translateUpstreamHealthCheckV2(au.HealthCheck, ups); err != nil {
- return nil, err
- }
- if err := t.translateUpstreamRetriesAndTimeoutV2(au.Retries, au.Timeout, ups); err != nil {
- return nil, err
- }
- if err := t.translateClientTLSV2(au.TLSSecret, ups); err != nil {
- return nil, err
- }
- return ups, nil
-}
-
-func (t *translator) TranslateUpstream(namespace, name, subset string, port int32) (*apisixv1.Upstream, error) {
- endpoint, err := t.EndpointLister.GetEndpoint(namespace, name)
- if err != nil {
- return nil, &translateError{
- field: "endpoints",
- reason: err.Error(),
- }
- }
-
- switch t.APIVersion {
- case config.ApisixV2beta3:
- return t.translateUpstreamV2beta3(&endpoint, namespace, name, subset, port)
- case config.ApisixV2:
- return t.translateUpstreamV2(&endpoint, namespace, name, subset, port)
- default:
- panic(fmt.Errorf("unsupported ApisixUpstream version %v", t.APIVersion))
- }
-}
-
-func (t *translator) translateUpstreamV2(ep *kube.Endpoint, namespace, name, subset string, port int32) (*apisixv1.Upstream, error) {
- au, err := t.ApisixUpstreamLister.V2(namespace, name)
- ups := apisixv1.NewDefaultUpstream()
- if err != nil {
- if k8serrors.IsNotFound(err) {
- // If subset in ApisixRoute is not empty but the ApisixUpstream resource not found,
- // just set an empty node list.
- if subset != "" {
- ups.Nodes = apisixv1.UpstreamNodes{}
- return ups, nil
- }
- } else {
- return nil, &translateError{
- field: "ApisixUpstream",
- reason: err.Error(),
- }
- }
- }
- var labels types.Labels
- if subset != "" {
- for _, ss := range au.V2().Spec.Subsets {
- if ss.Name == subset {
- labels = ss.Labels
- break
- }
- }
- }
- // Filter nodes by subset.
- nodes, err := t.TranslateUpstreamNodes(*ep, port, labels)
- if err != nil {
- return nil, err
- }
- if au == nil || au.V2().Spec == nil {
- ups.Nodes = nodes
- return ups, nil
- }
-
- upsCfg := &au.V2().Spec.ApisixUpstreamConfig
- for _, pls := range au.V2().Spec.PortLevelSettings {
- if pls.Port == port {
- upsCfg = &pls.ApisixUpstreamConfig
- break
- }
- }
- ups, err = t.TranslateUpstreamConfigV2(upsCfg)
- if err != nil {
- return nil, err
- }
- ups.Nodes = nodes
- return ups, nil
-}
-
-func (t *translator) translateUpstreamV2beta3(ep *kube.Endpoint, namespace, name, subset string, port int32) (*apisixv1.Upstream, error) {
- au, err := t.ApisixUpstreamLister.V2beta3(namespace, name)
- ups := apisixv1.NewDefaultUpstream()
- if err != nil {
- if k8serrors.IsNotFound(err) {
- // If subset in ApisixRoute is not empty but the ApisixUpstream resource not found,
- // just set an empty node list.
- if subset != "" {
- ups.Nodes = apisixv1.UpstreamNodes{}
- return ups, nil
- }
- } else {
- return nil, &translateError{
- field: "ApisixUpstream",
- reason: err.Error(),
- }
- }
- }
- if err != nil {
- if k8serrors.IsNotFound(err) {
- // If subset in ApisixRoute is not empty but the ApisixUpstream resource not found,
- // just set an empty node list.
- if subset != "" {
- ups.Nodes = apisixv1.UpstreamNodes{}
- return ups, nil
- }
- } else {
- return nil, &translateError{
- field: "ApisixUpstream",
- reason: err.Error(),
- }
- }
- }
- var labels types.Labels
- if subset != "" {
- for _, ss := range au.V2beta3().Spec.Subsets {
- if ss.Name == subset {
- labels = ss.Labels
- break
- }
- }
- }
- // Filter nodes by subset.
- nodes, err := t.TranslateUpstreamNodes(*ep, port, labels)
- if err != nil {
- return nil, err
- }
- if au == nil || au.V2beta3().Spec == nil {
- ups.Nodes = nodes
- return ups, nil
- }
-
- upsCfg := &au.V2beta3().Spec.ApisixUpstreamConfig
- for _, pls := range au.V2beta3().Spec.PortLevelSettings {
- if pls.Port == port {
- upsCfg = &pls.ApisixUpstreamConfig
- break
- }
- }
- ups, err = t.TranslateUpstreamConfigV2beta3(upsCfg)
- if err != nil {
- return nil, err
- }
- ups.Nodes = nodes
- return ups, nil
-}
-
-func (t *translator) TranslateUpstreamNodes(endpoint kube.Endpoint, port int32, labels types.Labels) (apisixv1.UpstreamNodes, error) {
- namespace, err := endpoint.Namespace()
- if err != nil {
- log.Errorw("failed to get endpoint namespace",
- zap.Error(err),
- zap.Any("endpoint", endpoint),
- )
- return nil, err
- }
- svcName := endpoint.ServiceName()
- svc, err := t.ServiceLister.Services(namespace).Get(svcName)
- if err != nil {
- return nil, &translateError{
- field: "service",
- reason: err.Error(),
- }
- }
-
- var svcPort *corev1.ServicePort
- for _, exposePort := range svc.Spec.Ports {
- if exposePort.Port == port {
- svcPort = &exposePort
- break
- }
- }
- if svcPort == nil {
- return nil, &translateError{
- field: "service.spec.ports",
- reason: "port not defined",
- }
- }
- // As nodes is not optional, here we create an empty slice,
- // not a nil slice.
- nodes := make(apisixv1.UpstreamNodes, 0)
- for _, hostport := range endpoint.Endpoints(svcPort) {
- nodes = append(nodes, apisixv1.UpstreamNode{
- Host: hostport.Host,
- Port: hostport.Port,
- // FIXME Custom node weight
- Weight: _defaultWeight,
- })
- }
- if labels != nil {
- nodes = t.filterNodesByLabels(nodes, labels, namespace)
- return nodes, nil
- }
- return nodes, nil
-}
-
-func (t *translator) TranslateIngress(ing kube.Ingress, args ...bool) (*TranslateContext, error) {
- var skipVerify = false
- if len(args) != 0 {
- skipVerify = args[0]
- }
- switch ing.GroupVersion() {
- case kube.IngressV1:
- return t.translateIngressV1(ing.V1(), skipVerify)
- case kube.IngressV1beta1:
- return t.translateIngressV1beta1(ing.V1beta1(), skipVerify)
- case kube.IngressExtensionsV1beta1:
- return t.translateIngressExtensionsV1beta1(ing.ExtensionsV1beta1(), skipVerify)
- default:
- return nil, fmt.Errorf("translator: source group version not supported: %s", ing.GroupVersion())
- }
-}
-
-func (t *translator) TranslateOldRoute(ar kube.ApisixRoute) (*TranslateContext, error) {
- switch ar.GroupVersion() {
- case config.ApisixV2:
- return t.translateOldRouteV2(ar.V2())
- case config.ApisixV2beta3:
- return t.translateOldRouteV2beta3(ar.V2beta3())
- case config.ApisixV2beta2:
- return DefaultEmptyTranslateContext(), nil
- default:
- return nil, fmt.Errorf("translator: source group version not supported: %s", ar.GroupVersion())
- }
-}
-
-func (t *translator) TranslateOldIngress(ing kube.Ingress) (*TranslateContext, error) {
- switch ing.GroupVersion() {
- case kube.IngressV1:
- return t.translateOldIngressV1(ing.V1())
- case kube.IngressV1beta1:
- return t.translateOldIngressV1beta1(ing.V1beta1())
- case kube.IngressExtensionsV1beta1:
- return t.translateOldIngressExtensionsv1beta1(ing.ExtensionsV1beta1())
- default:
- return nil, fmt.Errorf("translator: source group version not supported: %s", ing.GroupVersion())
- }
-}
diff --git a/pkg/kube/translation/util.go b/pkg/kube/translation/util.go
deleted file mode 100644
index 2ce379b8..00000000
--- a/pkg/kube/translation/util.go
+++ /dev/null
@@ -1,263 +0,0 @@
-// 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 translation
-
-import (
- "errors"
- "net"
-
- "go.uber.org/zap"
- "k8s.io/apimachinery/pkg/util/intstr"
-
- "github.com/apache/apisix-ingress-controller/pkg/id"
- configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
- configv2beta2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta2"
- configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
- "github.com/apache/apisix-ingress-controller/pkg/log"
- "github.com/apache/apisix-ingress-controller/pkg/types"
- apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
-)
-
-var (
- _errInvalidAddress = errors.New("address is neither IP or CIDR")
-)
-
-func (t *translator) getServiceClusterIPAndPort(backend *configv2.ApisixRouteHTTPBackend, ns string) (string, int32, error) {
- svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
- if err != nil {
- return "", 0, err
- }
- svcPort := int32(-1)
- if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
- log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
- zap.Any("namespace", ns),
- zap.Any("service", svc),
- )
- return "", 0, errors.New("conflict headless service and backend resolve granularity")
- }
-loop:
- for _, port := range svc.Spec.Ports {
- switch backend.ServicePort.Type {
- case intstr.Int:
- if backend.ServicePort.IntVal == port.Port {
- svcPort = port.Port
- break loop
- }
- case intstr.String:
- if backend.ServicePort.StrVal == port.Name {
- svcPort = port.Port
- break loop
- }
- }
- }
- if svcPort == -1 {
- log.Errorw("ApisixRoute refers to non-existent Service port",
- zap.String("namespace", ns),
- zap.String("port", backend.ServicePort.String()),
- )
- return "", 0, err
- }
-
- return svc.Spec.ClusterIP, svcPort, nil
-}
-
-// getStreamServiceClusterIPAndPortV2beta2 is for v2beta2 streamRoute
-func (t *translator) getStreamServiceClusterIPAndPortV2beta2(backend configv2beta2.ApisixRouteStreamBackend, ns string) (string, int32, error) {
- svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
- if err != nil {
- return "", 0, err
- }
- svcPort := int32(-1)
- if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
- log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
- zap.String("ApisixRoute namespace", ns),
- zap.Any("service", svc),
- )
- return "", 0, errors.New("conflict headless service and backend resolve granularity")
- }
-loop:
- for _, port := range svc.Spec.Ports {
- switch backend.ServicePort.Type {
- case intstr.Int:
- if backend.ServicePort.IntVal == port.Port {
- svcPort = port.Port
- break loop
- }
- case intstr.String:
- if backend.ServicePort.StrVal == port.Name {
- svcPort = port.Port
- break loop
- }
- }
- }
- if svcPort == -1 {
- log.Errorw("ApisixRoute refers to non-existent Service port",
- zap.String("ApisixRoute namespace", ns),
- zap.String("port", backend.ServicePort.String()),
- )
- return "", 0, err
- }
-
- return svc.Spec.ClusterIP, svcPort, nil
-}
-
-// getStreamServiceClusterIPAndPortV2beta3 is for v2beta3 streamRoute
-func (t *translator) getStreamServiceClusterIPAndPortV2beta3(backend configv2beta3.ApisixRouteStreamBackend, ns string) (string, int32, error) {
- svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
- if err != nil {
- return "", 0, err
- }
- svcPort := int32(-1)
- if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
- log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
- zap.String("ApisixRoute namespace", ns),
- zap.Any("service", svc),
- )
- return "", 0, errors.New("conflict headless service and backend resolve granularity")
- }
-loop:
- for _, port := range svc.Spec.Ports {
- switch backend.ServicePort.Type {
- case intstr.Int:
- if backend.ServicePort.IntVal == port.Port {
- svcPort = port.Port
- break loop
- }
- case intstr.String:
- if backend.ServicePort.StrVal == port.Name {
- svcPort = port.Port
- break loop
- }
- }
- }
- if svcPort == -1 {
- log.Errorw("ApisixRoute refers to non-existent Service port",
- zap.String("ApisixRoute namespace", ns),
- zap.String("port", backend.ServicePort.String()),
- )
- return "", 0, err
- }
-
- return svc.Spec.ClusterIP, svcPort, nil
-}
-
-// getStreamServiceClusterIPAndPortV2 is for v2 streamRoute
-func (t *translator) getStreamServiceClusterIPAndPortV2(backend configv2.ApisixRouteStreamBackend, ns string) (string, int32, error) {
- svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
- if err != nil {
- return "", 0, err
- }
- svcPort := int32(-1)
- if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
- log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
- zap.String("ApisixRoute namespace", ns),
- zap.Any("service", svc),
- )
- return "", 0, errors.New("conflict headless service and backend resolve granularity")
- }
-loop:
- for _, port := range svc.Spec.Ports {
- switch backend.ServicePort.Type {
- case intstr.Int:
- if backend.ServicePort.IntVal == port.Port {
- svcPort = port.Port
- break loop
- }
- case intstr.String:
- if backend.ServicePort.StrVal == port.Name {
- svcPort = port.Port
- break loop
- }
- }
- }
- if svcPort == -1 {
- log.Errorw("ApisixRoute refers to non-existent Service port",
- zap.String("ApisixRoute namespace", ns),
- zap.String("port", backend.ServicePort.String()),
- )
- return "", 0, err
- }
-
- return svc.Spec.ClusterIP, svcPort, nil
-}
-
-// translateUpstreamNotStrictly translates Upstream nodes with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateUpstreamNotStrictly(namespace, svcName, subset string, svcPort int32) (*apisixv1.Upstream, error) {
- ups := &apisixv1.Upstream{}
- ups.Name = apisixv1.ComposeUpstreamName(namespace, svcName, subset, svcPort)
- ups.ID = id.GenID(ups.Name)
- return ups, nil
-}
-
-func (t *translator) translateUpstream(namespace, svcName, subset, svcResolveGranularity, svcClusterIP string, svcPort int32) (*apisixv1.Upstream, error) {
- ups, err := t.TranslateUpstream(namespace, svcName, subset, svcPort)
- if err != nil {
- return nil, err
- }
- if svcResolveGranularity == "service" {
- ups.Nodes = apisixv1.UpstreamNodes{
- {
- Host: svcClusterIP,
- Port: int(svcPort),
- Weight: _defaultWeight,
- },
- }
- }
- ups.Name = apisixv1.ComposeUpstreamName(namespace, svcName, subset, svcPort)
- ups.ID = id.GenID(ups.Name)
- return ups, nil
-}
-
-func (t *translator) filterNodesByLabels(nodes apisixv1.UpstreamNodes, labels types.Labels, namespace string) apisixv1.UpstreamNodes {
- if labels == nil {
- return nodes
- }
-
- filteredNodes := make(apisixv1.UpstreamNodes, 0)
- for _, node := range nodes {
- podName, err := t.PodCache.GetNameByIP(node.Host)
- if err != nil {
- log.Errorw("failed to find pod name by ip, ignore it",
- zap.Error(err),
- zap.String("pod_ip", node.Host),
- )
- continue
- }
- pod, err := t.PodLister.Pods(namespace).Get(podName)
- if err != nil {
- log.Errorw("failed to find pod, ignore it",
- zap.Error(err),
- zap.String("pod_name", podName),
- )
- continue
- }
- if labels.IsSubsetOf(pod.Labels) {
- filteredNodes = append(filteredNodes, node)
- }
- }
- return filteredNodes
-}
-
-func validateRemoteAddrs(remoteAddrs []string) error {
- for _, addr := range remoteAddrs {
- if ip := net.ParseIP(addr); ip == nil {
- // addr is not an IP address, try to parse it as a CIDR.
- if _, _, err := net.ParseCIDR(addr); err != nil {
- return _errInvalidAddress
- }
- }
- }
- return nil
-}
diff --git a/pkg/ingress/apisix_cluster_config.go b/pkg/providers/apisix/apisix_cluster_config.go
similarity index 63%
rename from pkg/ingress/apisix_cluster_config.go
rename to pkg/providers/apisix/apisix_cluster_config.go
index fa346381..d611cbb9 100644
--- a/pkg/ingress/apisix_cluster_config.go
+++ b/pkg/providers/apisix/apisix_cluster_config.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
@@ -22,37 +22,51 @@ import (
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"github.com/apache/apisix-ingress-controller/pkg/apisix"
"github.com/apache/apisix-ingress-controller/pkg/config"
"github.com/apache/apisix-ingress-controller/pkg/kube"
+ 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"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
type apisixClusterConfigController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *apisixCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ apisixClusterConfigLister kube.ApisixClusterConfigLister
+ apisixClusterConfigInformer cache.SharedIndexInformer
}
-func (c *Controller) newApisixClusterConfigController() *apisixClusterConfigController {
- ctl := &apisixClusterConfigController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(time.Second, 60*time.Second, 5), "ApisixClusterConfig"),
- workers: 1,
+func newApisixClusterConfigController(common *apisixCommon,
+ apisixClusterConfigInformer cache.SharedIndexInformer, apisixClusterConfigLister kube.ApisixClusterConfigLister) *apisixClusterConfigController {
+ c := &apisixClusterConfigController{
+ apisixCommon: common,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(time.Second, 60*time.Second, 5), "ApisixClusterConfig"),
+ workers: 1,
+
+ apisixClusterConfigLister: apisixClusterConfigLister,
+ apisixClusterConfigInformer: apisixClusterConfigInformer,
}
+
c.apisixClusterConfigInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
- return ctl
+ return c
}
func (c *apisixClusterConfigController) run(ctx context.Context) {
@@ -60,7 +74,7 @@ func (c *apisixClusterConfigController) run(ctx context.Context) {
defer log.Info("ApisixClusterConfig controller exited")
defer c.workqueue.ShutDown()
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.apisixClusterConfigInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.apisixClusterConfigInformer.HasSynced); !ok {
log.Error("cache sync failed")
return
}
@@ -94,9 +108,9 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
var multiVersioned kube.ApisixClusterConfig
switch event.GroupVersion {
case config.ApisixV2beta3:
- multiVersioned, err = c.controller.apisixClusterConfigLister.V2beta3(name)
+ multiVersioned, err = c.apisixClusterConfigLister.V2beta3(name)
case config.ApisixV2:
- multiVersioned, err = c.controller.apisixClusterConfigLister.V2(name)
+ multiVersioned, err = c.apisixClusterConfigLister.V2(name)
default:
return fmt.Errorf("unsupported ApisixClusterConfig group version %s", event.GroupVersion)
}
@@ -134,9 +148,9 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
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 {
+ if acc.Name != c.Config.APISIX.DefaultClusterName {
log.Infow("ignore non-default apisix cluster config",
- zap.String("default_cluster_name", c.controller.cfg.APISIX.DefaultClusterName),
+ zap.String("default_cluster_name", c.Config.APISIX.DefaultClusterName),
zap.Any("ApisixClusterConfig", acc),
)
return nil
@@ -159,27 +173,27 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
)
// 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 {
+ if err := c.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())
+ c.RecordEvent(acc, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(acc, utils.ResourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration())
return err
}
}
- globalRule, err := c.controller.translator.TranslateClusterConfigV2beta3(acc)
+ globalRule, err := c.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())
+ c.RecordEvent(acc, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(acc, utils.ResourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration())
return err
}
log.Debugw("translated global_rule",
@@ -188,29 +202,29 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
// TODO multiple cluster support
if ev.Type == types.EventAdd {
- _, err = c.controller.apisix.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
+ _, err = c.APISIX.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
} else {
- _, err = c.controller.apisix.Cluster(acc.Name).GlobalRule().Update(ctx, globalRule)
+ _, err = c.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())
+ c.RecordEvent(acc, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(acc, utils.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())
+ c.RecordEvent(acc, corev1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(acc, utils.ResourceSynced, nil, metav1.ConditionTrue, acc.GetGeneration())
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 {
+ if acc.Name != c.Config.APISIX.DefaultClusterName {
log.Infow("ignore non-default apisix cluster config",
- zap.String("default_cluster_name", c.controller.cfg.APISIX.DefaultClusterName),
+ zap.String("default_cluster_name", c.Config.APISIX.DefaultClusterName),
zap.Any("ApisixClusterConfig", acc),
)
return nil
@@ -233,27 +247,27 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
)
// 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 {
+ if err := c.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())
+ c.RecordEvent(acc, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(acc, utils.ResourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration())
return err
}
}
- globalRule, err := c.controller.translator.TranslateClusterConfigV2(acc)
+ globalRule, err := c.translator.TranslateClusterConfigV2(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())
+ c.RecordEvent(acc, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(acc, utils.ResourceSyncAborted, err, metav1.ConditionFalse, acc.GetGeneration())
return err
}
log.Debugw("translated global_rule",
@@ -262,21 +276,21 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
// TODO multiple cluster support
if ev.Type == types.EventAdd {
- _, err = c.controller.apisix.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
+ _, err = c.APISIX.Cluster(acc.Name).GlobalRule().Create(ctx, globalRule)
} else {
- _, err = c.controller.apisix.Cluster(acc.Name).GlobalRule().Update(ctx, globalRule)
+ _, err = c.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())
+ c.RecordEvent(acc, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(acc, utils.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())
+ c.RecordEvent(acc, corev1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(acc, utils.ResourceSynced, nil, metav1.ConditionTrue, acc.GetGeneration())
return nil
default:
return fmt.Errorf("unsupported ApisixClusterConfig group version %s", event.GroupVersion)
@@ -286,7 +300,7 @@ func (c *apisixClusterConfigController) sync(ctx context.Context, ev *types.Even
func (c *apisixClusterConfigController) handleSyncErr(obj interface{}, err error) {
if err == nil {
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("clusterConfig", "success")
+ c.MetricsCollector.IncrSyncOperation("clusterConfig", "success")
return
}
event := obj.(*types.Event)
@@ -304,7 +318,7 @@ func (c *apisixClusterConfigController) handleSyncErr(obj interface{}, err error
)
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("clusterConfig", "failure")
+ c.MetricsCollector.IncrSyncOperation("clusterConfig", "failure")
}
func (c *apisixClusterConfigController) onAdd(obj interface{}) {
@@ -331,7 +345,7 @@ func (c *apisixClusterConfigController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("clusterConfig", "add")
+ c.MetricsCollector.IncrEvents("clusterConfig", "add")
}
func (c *apisixClusterConfigController) onUpdate(oldObj, newObj interface{}) {
@@ -367,7 +381,7 @@ func (c *apisixClusterConfigController) onUpdate(oldObj, newObj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("clusterConfig", "update")
+ c.MetricsCollector.IncrEvents("clusterConfig", "update")
}
func (c *apisixClusterConfigController) onDelete(obj interface{}) {
@@ -401,18 +415,18 @@ func (c *apisixClusterConfigController) onDelete(obj interface{}) {
Tombstone: acc,
})
- c.controller.MetricsCollector.IncrEvents("clusterConfig", "delete")
+ c.MetricsCollector.IncrEvents("clusterConfig", "delete")
}
func (c *apisixClusterConfigController) ResourceSync() {
- objs := c.controller.apisixClusterConfigInformer.GetIndexer().List()
+ objs := c.apisixClusterConfigInformer.GetIndexer().List()
for _, obj := range objs {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
log.Errorw("ApisixClusterConfig sync failed, found ApisixClusterConfig resource with bad meta namespace key", zap.String("error", err.Error()))
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
acc, err := kube.NewApisixClusterConfig(obj)
@@ -429,3 +443,62 @@ func (c *apisixClusterConfigController) ResourceSync() {
})
}
}
+
+// recordStatus record resources status
+func (c *apisixClusterConfigController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2beta3.ApisixClusterConfig:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta3().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 *configv2.ApisixClusterConfig:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.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),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/ingress/apisix_consumer.go b/pkg/providers/apisix/apisix_consumer.go
similarity index 61%
rename from pkg/ingress/apisix_consumer.go
rename to pkg/providers/apisix/apisix_consumer.go
index 581239dd..b2f94a19 100644
--- a/pkg/ingress/apisix_consumer.go
+++ b/pkg/providers/apisix/apisix_consumer.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
@@ -22,42 +22,56 @@ import (
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"github.com/apache/apisix-ingress-controller/pkg/config"
"github.com/apache/apisix-ingress-controller/pkg/kube"
+ 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"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
type apisixConsumerController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *apisixCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ apisixConsumerLister kube.ApisixConsumerLister
+ apisixConsumerInformer cache.SharedIndexInformer
}
-func (c *Controller) newApisixConsumerController() *apisixConsumerController {
- ctl := &apisixConsumerController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixConsumer"),
- workers: 1,
+func newApisixConsumerController(common *apisixCommon,
+ apisixConsumerInformer cache.SharedIndexInformer, apisixConsumerLister kube.ApisixConsumerLister) *apisixConsumerController {
+ c := &apisixConsumerController{
+ apisixCommon: common,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixConsumer"),
+ workers: 1,
+
+ apisixConsumerLister: apisixConsumerLister,
+ apisixConsumerInformer: apisixConsumerInformer,
}
- ctl.controller.apisixConsumerInformer.AddEventHandler(
+
+ c.apisixConsumerInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
- return ctl
+ return c
}
func (c *apisixConsumerController) run(ctx context.Context) {
log.Info("ApisixConsumer controller started")
defer log.Info("ApisixConsumer controller exited")
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.apisixConsumerInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.apisixConsumerInformer.HasSynced); !ok {
log.Error("cache sync failed")
return
}
@@ -92,9 +106,9 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er
var multiVersioned kube.ApisixConsumer
switch event.GroupVersion {
case config.ApisixV2beta3:
- multiVersioned, err = c.controller.apisixConsumerLister.V2beta3(namespace, name)
+ multiVersioned, err = c.apisixConsumerLister.V2beta3(namespace, name)
case config.ApisixV2:
- multiVersioned, err = c.controller.apisixConsumerLister.V2(namespace, name)
+ multiVersioned, err = c.apisixConsumerLister.V2(namespace, name)
default:
return fmt.Errorf("unsupported ApisixConsumer group version %s", event.GroupVersion)
}
@@ -132,14 +146,14 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er
case config.ApisixV2beta3:
ac := multiVersioned.V2beta3()
- consumer, err := c.controller.translator.TranslateApisixConsumerV2beta3(ac)
+ consumer, err := c.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())
+ c.RecordEvent(ac, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(ac, utils.ResourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
return err
}
log.Debugw("got consumer object from ApisixConsumer",
@@ -147,28 +161,28 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er
zap.Any("ApisixConsumer", ac),
)
- if err := c.controller.syncConsumer(ctx, consumer, ev.Type); err != nil {
+ if err := c.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())
+ c.RecordEvent(ac, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(ac, utils.ResourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
return err
}
- c.controller.recorderEvent(ac, corev1.EventTypeNormal, _resourceSynced, nil)
+ c.RecordEvent(ac, corev1.EventTypeNormal, utils.ResourceSynced, nil)
case config.ApisixV2:
ac := multiVersioned.V2()
- consumer, err := c.controller.translator.TranslateApisixConsumerV2(ac)
+ consumer, err := c.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())
+ c.RecordEvent(ac, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(ac, utils.ResourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
return err
}
log.Debugw("got consumer object from ApisixConsumer",
@@ -176,17 +190,17 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er
zap.Any("ApisixConsumer", ac),
)
- if err := c.controller.syncConsumer(ctx, consumer, ev.Type); err != nil {
+ if err := c.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())
+ c.RecordEvent(ac, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(ac, utils.ResourceSyncAborted, err, metav1.ConditionFalse, ac.GetGeneration())
return err
}
- c.controller.recorderEvent(ac, corev1.EventTypeNormal, _resourceSynced, nil)
+ c.RecordEvent(ac, corev1.EventTypeNormal, utils.ResourceSynced, nil)
}
return nil
}
@@ -194,7 +208,7 @@ func (c *apisixConsumerController) sync(ctx context.Context, ev *types.Event) er
func (c *apisixConsumerController) handleSyncErr(obj interface{}, err error) {
if err == nil {
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("consumer", "success")
+ c.MetricsCollector.IncrSyncOperation("consumer", "success")
return
}
event := obj.(*types.Event)
@@ -211,7 +225,7 @@ func (c *apisixConsumerController) handleSyncErr(obj interface{}, err error) {
zap.Error(err),
)
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("consumer", "failure")
+ c.MetricsCollector.IncrSyncOperation("consumer", "failure")
}
func (c *apisixConsumerController) onAdd(obj interface{}) {
@@ -225,7 +239,7 @@ func (c *apisixConsumerController) onAdd(obj interface{}) {
log.Errorf("found ApisixConsumer resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixConsumer add event arrived",
@@ -240,7 +254,7 @@ func (c *apisixConsumerController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("consumer", "add")
+ c.MetricsCollector.IncrEvents("consumer", "add")
}
func (c *apisixConsumerController) onUpdate(oldObj, newObj interface{}) {
@@ -262,7 +276,7 @@ func (c *apisixConsumerController) onUpdate(oldObj, newObj interface{}) {
log.Errorf("found ApisixConsumer resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixConsumer update event arrived",
@@ -279,7 +293,7 @@ func (c *apisixConsumerController) onUpdate(oldObj, newObj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("consumer", "update")
+ c.MetricsCollector.IncrEvents("consumer", "update")
}
func (c *apisixConsumerController) onDelete(obj interface{}) {
@@ -301,7 +315,7 @@ func (c *apisixConsumerController) onDelete(obj interface{}) {
log.Errorf("found ApisixConsumer resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixConsumer delete event arrived",
@@ -316,18 +330,18 @@ func (c *apisixConsumerController) onDelete(obj interface{}) {
Tombstone: ac,
})
- c.controller.MetricsCollector.IncrEvents("consumer", "delete")
+ c.MetricsCollector.IncrEvents("consumer", "delete")
}
func (c *apisixConsumerController) ResourceSync() {
- objs := c.controller.apisixConsumerInformer.GetIndexer().List()
+ objs := c.apisixConsumerInformer.GetIndexer().List()
for _, obj := range objs {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
log.Errorw("ApisixConsumer sync failed, found ApisixConsumer resource with bad meta namespace key", zap.String("error", err.Error()))
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
ac, err := kube.NewApisixConsumer(obj)
@@ -344,3 +358,64 @@ func (c *apisixConsumerController) ResourceSync() {
})
}
}
+
+// recordStatus record resources status
+func (c *apisixConsumerController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2beta3.ApisixConsumer:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta3().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 *configv2.ApisixConsumer:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.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),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/ingress/apisix_pluginconfig.go b/pkg/providers/apisix/apisix_plugin_config.go
similarity index 61%
rename from pkg/ingress/apisix_pluginconfig.go
rename to pkg/providers/apisix/apisix_plugin_config.go
index fa7e64a7..ea20a719 100644
--- a/pkg/ingress/apisix_pluginconfig.go
+++ b/pkg/providers/apisix/apisix_plugin_config.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
@@ -22,38 +22,51 @@ import (
"go.uber.org/zap"
v1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"github.com/apache/apisix-ingress-controller/pkg/config"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
"github.com/apache/apisix-ingress-controller/pkg/kube"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
+ 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"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
type apisixPluginConfigController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *apisixCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ apisixPluginConfigLister kube.ApisixPluginConfigLister
+ apisixPluginConfigInformer cache.SharedIndexInformer
}
-func (c *Controller) newApisixPluginConfigController() *apisixPluginConfigController {
- ctl := &apisixPluginConfigController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixPluginConfig"),
- workers: 1,
+func newApisixPluginConfigController(common *apisixCommon,
+ apisixPluginConfigInformer cache.SharedIndexInformer, apisixPluginConfigLister kube.ApisixPluginConfigLister) *apisixPluginConfigController {
+ c := &apisixPluginConfigController{
+ apisixCommon: common,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixPluginConfig"),
+ workers: 1,
+
+ apisixPluginConfigLister: apisixPluginConfigLister,
+ apisixPluginConfigInformer: apisixPluginConfigInformer,
}
+
c.apisixPluginConfigInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
- return ctl
+ return c
}
func (c *apisixPluginConfigController) run(ctx context.Context) {
@@ -61,7 +74,7 @@ func (c *apisixPluginConfigController) run(ctx context.Context) {
defer log.Info("ApisixPluginConfig controller exited")
defer c.workqueue.ShutDown()
- ok := cache.WaitForCacheSync(ctx.Done(), c.controller.apisixPluginConfigInformer.HasSynced)
+ ok := cache.WaitForCacheSync(ctx.Done(), c.apisixPluginConfigInformer.HasSynced)
if !ok {
log.Error("cache sync failed")
return
@@ -98,9 +111,9 @@ func (c *apisixPluginConfigController) sync(ctx context.Context, ev *types.Event
)
switch obj.GroupVersion {
case config.ApisixV2beta3:
- apc, err = c.controller.apisixPluginConfigLister.V2beta3(namespace, name)
+ apc, err = c.apisixPluginConfigLister.V2beta3(namespace, name)
case config.ApisixV2:
- apc, err = c.controller.apisixPluginConfigLister.V2(namespace, name)
+ apc, err = c.apisixPluginConfigLister.V2(namespace, name)
default:
return fmt.Errorf("unsupported ApisixPluginConfig group version %s", obj.GroupVersion)
}
@@ -138,9 +151,9 @@ func (c *apisixPluginConfigController) sync(ctx context.Context, ev *types.Event
switch obj.GroupVersion {
case config.ApisixV2beta3:
if ev.Type != types.EventDelete {
- tctx, err = c.controller.translator.TranslatePluginConfigV2beta3(apc.V2beta3())
+ tctx, err = c.translator.TranslatePluginConfigV2beta3(apc.V2beta3())
} else {
- tctx, err = c.controller.translator.TranslatePluginConfigV2beta3NotStrictly(apc.V2beta3())
+ tctx, err = c.translator.TranslatePluginConfigV2beta3NotStrictly(apc.V2beta3())
}
if err != nil {
log.Errorw("failed to translate ApisixPluginConfig v2beta3",
@@ -151,9 +164,9 @@ func (c *apisixPluginConfigController) sync(ctx context.Context, ev *types.Event
}
case config.ApisixV2:
if ev.Type != types.EventDelete {
- tctx, err = c.controller.translator.TranslatePluginConfigV2(apc.V2())
+ tctx, err = c.translator.TranslatePluginConfigV2(apc.V2())
} else {
- tctx, err = c.controller.translator.TranslatePluginConfigV2NotStrictly(apc.V2())
+ tctx, err = c.translator.TranslatePluginConfigV2NotStrictly(apc.V2())
}
if err != nil {
log.Errorw("failed to translate ApisixPluginConfig v2",
@@ -186,9 +199,9 @@ func (c *apisixPluginConfigController) sync(ctx context.Context, ev *types.Event
var oldCtx *translation.TranslateContext
switch obj.GroupVersion {
case config.ApisixV2beta3:
- oldCtx, err = c.controller.translator.TranslatePluginConfigV2beta3(obj.OldObject.V2beta3())
+ oldCtx, err = c.translator.TranslatePluginConfigV2beta3(obj.OldObject.V2beta3())
case config.ApisixV2:
- oldCtx, err = c.controller.translator.TranslatePluginConfigV2(obj.OldObject.V2())
+ oldCtx, err = c.translator.TranslatePluginConfigV2(obj.OldObject.V2())
}
if err != nil {
log.Errorw("failed to translate old ApisixPluginConfig",
@@ -206,7 +219,7 @@ func (c *apisixPluginConfigController) sync(ctx context.Context, ev *types.Event
added, updated, deleted = m.Diff(om)
}
- return c.controller.syncManifests(ctx, added, updated, deleted)
+ return c.SyncManifests(ctx, added, updated, deleted)
}
func (c *apisixPluginConfigController) handleSyncErr(obj interface{}, errOrigin error) {
@@ -223,15 +236,15 @@ func (c *apisixPluginConfigController) handleSyncErr(obj interface{}, errOrigin
namespace, name, errLocal := cache.SplitMetaNamespaceKey(event.Key)
if errLocal != nil {
log.Errorf("invalid resource key: %s", event.Key)
- c.controller.MetricsCollector.IncrSyncOperation("PluginConfig", "failure")
+ c.MetricsCollector.IncrSyncOperation("PluginConfig", "failure")
return
}
var apc kube.ApisixPluginConfig
switch event.GroupVersion {
case config.ApisixV2beta3:
- apc, errLocal = c.controller.apisixPluginConfigLister.V2beta3(namespace, name)
+ apc, errLocal = c.apisixPluginConfigLister.V2beta3(namespace, name)
case config.ApisixV2:
- apc, errLocal = c.controller.apisixPluginConfigLister.V2(namespace, name)
+ apc, errLocal = c.apisixPluginConfigLister.V2(namespace, name)
default:
errLocal = fmt.Errorf("unsupported ApisixPluginConfig group version %s", event.GroupVersion)
}
@@ -240,11 +253,11 @@ func (c *apisixPluginConfigController) handleSyncErr(obj interface{}, errOrigin
if errLocal == nil {
switch apc.GroupVersion() {
case config.ApisixV2beta3:
- c.controller.recorderEvent(apc.V2beta3(), v1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(apc.V2beta3(), _resourceSynced, nil, metav1.ConditionTrue, apc.V2beta3().GetGeneration())
+ c.RecordEvent(apc.V2beta3(), v1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(apc.V2beta3(), utils.ResourceSynced, nil, metav1.ConditionTrue, apc.V2beta3().GetGeneration())
case config.ApisixV2:
- c.controller.recorderEvent(apc.V2(), v1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(apc.V2(), _resourceSynced, nil, metav1.ConditionTrue, apc.V2().GetGeneration())
+ c.RecordEvent(apc.V2(), v1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(apc.V2(), utils.ResourceSynced, nil, metav1.ConditionTrue, apc.V2().GetGeneration())
}
} else {
log.Errorw("failed list ApisixPluginConfig",
@@ -255,7 +268,7 @@ func (c *apisixPluginConfigController) handleSyncErr(obj interface{}, errOrigin
}
}
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("PluginConfig", "success")
+ c.MetricsCollector.IncrSyncOperation("PluginConfig", "success")
return
}
log.Warnw("sync ApisixPluginConfig failed, will retry",
@@ -265,11 +278,11 @@ func (c *apisixPluginConfigController) handleSyncErr(obj interface{}, errOrigin
if errLocal == nil {
switch apc.GroupVersion() {
case config.ApisixV2beta3:
- c.controller.recorderEvent(apc.V2beta3(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
- c.controller.recordStatus(apc.V2beta3(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, apc.V2beta3().GetGeneration())
+ c.RecordEvent(apc.V2beta3(), v1.EventTypeWarning, utils.ResourceSyncAborted, errOrigin)
+ c.recordStatus(apc.V2beta3(), utils.ResourceSyncAborted, errOrigin, metav1.ConditionFalse, apc.V2beta3().GetGeneration())
case config.ApisixV2:
- c.controller.recorderEvent(apc.V2(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
- c.controller.recordStatus(apc.V2(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, apc.V2().GetGeneration())
+ c.RecordEvent(apc.V2(), v1.EventTypeWarning, utils.ResourceSyncAborted, errOrigin)
+ c.recordStatus(apc.V2(), utils.ResourceSyncAborted, errOrigin, metav1.ConditionFalse, apc.V2().GetGeneration())
}
} else {
log.Errorw("failed list ApisixPluginConfig",
@@ -279,7 +292,7 @@ func (c *apisixPluginConfigController) handleSyncErr(obj interface{}, errOrigin
)
}
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("PluginConfig", "failure")
+ c.MetricsCollector.IncrSyncOperation("PluginConfig", "failure")
}
func (c *apisixPluginConfigController) onAdd(obj interface{}) {
@@ -288,7 +301,7 @@ func (c *apisixPluginConfigController) onAdd(obj interface{}) {
log.Errorf("found ApisixPluginConfig resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixPluginConfig add event arrived",
@@ -303,7 +316,7 @@ func (c *apisixPluginConfigController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("PluginConfig", "add")
+ c.MetricsCollector.IncrEvents("PluginConfig", "add")
}
func (c *apisixPluginConfigController) onUpdate(oldObj, newObj interface{}) {
@@ -317,7 +330,7 @@ func (c *apisixPluginConfigController) onUpdate(oldObj, newObj interface{}) {
log.Errorf("found ApisixPluginConfig resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixPluginConfig update event arrived",
@@ -333,7 +346,7 @@ func (c *apisixPluginConfigController) onUpdate(oldObj, newObj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("PluginConfig", "update")
+ c.MetricsCollector.IncrEvents("PluginConfig", "update")
}
func (c *apisixPluginConfigController) onDelete(obj interface{}) {
@@ -350,7 +363,7 @@ func (c *apisixPluginConfigController) onDelete(obj interface{}) {
log.Errorf("found ApisixPluginConfig resource with bad meta namesapce key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixPluginConfig delete event arrived",
@@ -365,18 +378,18 @@ func (c *apisixPluginConfigController) onDelete(obj interface{}) {
Tombstone: apc,
})
- c.controller.MetricsCollector.IncrEvents("PluginConfig", "delete")
+ c.MetricsCollector.IncrEvents("PluginConfig", "delete")
}
func (c *apisixPluginConfigController) ResourceSync() {
- objs := c.controller.apisixPluginConfigInformer.GetIndexer().List()
+ objs := c.apisixPluginConfigInformer.GetIndexer().List()
for _, obj := range objs {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
log.Errorw("ApisixPluginConfig sync failed, found ApisixPluginConfig resource with bad meta namespace key", zap.String("error", err.Error()))
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
apc := kube.MustNewApisixPluginConfig(obj)
@@ -389,3 +402,64 @@ func (c *apisixPluginConfigController) ResourceSync() {
})
}
}
+
+// recordStatus record resources status
+func (c *apisixPluginConfigController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2beta3.ApisixPluginConfig:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta3().ApisixPluginConfigs(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixPluginConfig",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ case *configv2.ApisixPluginConfig:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2().ApisixPluginConfigs(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixPluginConfig",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/ingress/apisix_route.go b/pkg/providers/apisix/apisix_route.go
similarity index 66%
rename from pkg/ingress/apisix_route.go
rename to pkg/providers/apisix/apisix_route.go
index 28c51a87..9f0e37cd 100644
--- a/pkg/ingress/apisix_route.go
+++ b/pkg/providers/apisix/apisix_route.go
@@ -12,64 +12,76 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
+ "fmt"
"sync"
"time"
"go.uber.org/zap"
v1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
apisixcache "github.com/apache/apisix-ingress-controller/pkg/apisix/cache"
"github.com/apache/apisix-ingress-controller/pkg/config"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
"github.com/apache/apisix-ingress-controller/pkg/kube"
v2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ configv2beta2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta2"
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
type apisixRouteController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *apisixCommon
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ svcInformer cache.SharedIndexInformer
+ apisixRouteLister kube.ApisixRouteLister
+ apisixRouteInformer cache.SharedIndexInformer
- // svc meta key -> ApisixRoute name -> empty
svcLock sync.RWMutex
svcMap map[string]map[string]struct{}
}
-func (c *Controller) newApisixRouteController() *apisixRouteController {
- ctl := &apisixRouteController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixRoute"),
- workers: 1,
+func newApisixRouteController(common *apisixCommon, apisixRouteInformer cache.SharedIndexInformer, apisixRouteLister kube.ApisixRouteLister) *apisixRouteController {
+ c := &apisixRouteController{
+ apisixCommon: common,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixRoute"),
+ workers: 1,
+
+ svcInformer: common.SvcInformer,
+ apisixRouteLister: apisixRouteLister,
+ apisixRouteInformer: apisixRouteInformer,
svcMap: make(map[string]map[string]struct{}),
}
+
c.apisixRouteInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
c.svcInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onSvcAdd,
+ AddFunc: c.onSvcAdd,
},
)
- return ctl
+ return c
}
func (c *apisixRouteController) run(ctx context.Context) {
@@ -77,7 +89,7 @@ func (c *apisixRouteController) run(ctx context.Context) {
defer log.Info("ApisixRoute controller exited")
defer c.workqueue.ShutDown()
- ok := cache.WaitForCacheSync(ctx.Done(), c.controller.apisixRouteInformer.HasSynced, c.controller.svcInformer.HasSynced)
+ ok := cache.WaitForCacheSync(ctx.Done(), c.apisixRouteInformer.HasSynced, c.svcInformer.HasSynced)
if !ok {
log.Error("cache sync failed")
return
@@ -179,6 +191,11 @@ func (c *apisixRouteController) syncServiceRelationship(ev *types.Event, name st
}
}
}
+ default:
+ log.Errorw("unknown ApisixRoute version",
+ zap.String("version", obj.GroupVersion),
+ zap.String("key", obj.Key),
+ )
}
// NOTE:
@@ -215,11 +232,17 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
)
switch obj.GroupVersion {
case config.ApisixV2beta2:
- ar, err = c.controller.apisixRouteLister.V2beta2(namespace, name)
+ ar, err = c.apisixRouteLister.V2beta2(namespace, name)
case config.ApisixV2beta3:
- ar, err = c.controller.apisixRouteLister.V2beta3(namespace, name)
+ ar, err = c.apisixRouteLister.V2beta3(namespace, name)
case config.ApisixV2:
- ar, err = c.controller.apisixRouteLister.V2(namespace, name)
+ ar, err = c.apisixRouteLister.V2(namespace, name)
+ default:
+ log.Errorw("unknown ApisixRoute version",
+ zap.String("version", obj.GroupVersion),
+ zap.String("key", obj.Key),
+ )
+ return fmt.Errorf("unknown ApisixRoute version %v", obj.GroupVersion)
}
if err != nil {
if !k8serrors.IsNotFound(err) {
@@ -258,9 +281,9 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
switch obj.GroupVersion {
case config.ApisixV2beta2:
if ev.Type != types.EventDelete {
- tctx, err = c.controller.translator.TranslateRouteV2beta2(ar.V2beta2())
+ tctx, err = c.translator.TranslateRouteV2beta2(ar.V2beta2())
} else {
- tctx, err = c.controller.translator.TranslateRouteV2beta2NotStrictly(ar.V2beta2())
+ tctx, err = c.translator.TranslateRouteV2beta2NotStrictly(ar.V2beta2())
}
if err != nil {
log.Errorw("failed to translate ApisixRoute v2beta2",
@@ -272,10 +295,10 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
case config.ApisixV2beta3:
if ev.Type != types.EventDelete {
if err = c.checkPluginNameIfNotEmptyV2beta3(ctx, ar.V2beta3()); err == nil {
- tctx, err = c.controller.translator.TranslateRouteV2beta3(ar.V2beta3())
+ tctx, err = c.translator.TranslateRouteV2beta3(ar.V2beta3())
}
} else {
- tctx, err = c.controller.translator.TranslateRouteV2beta3NotStrictly(ar.V2beta3())
+ tctx, err = c.translator.TranslateRouteV2beta3NotStrictly(ar.V2beta3())
}
if err != nil {
log.Errorw("failed to translate ApisixRoute v2beta3",
@@ -287,10 +310,10 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
case config.ApisixV2:
if ev.Type != types.EventDelete {
if err = c.checkPluginNameIfNotEmptyV2(ctx, ar.V2()); err == nil {
- tctx, err = c.controller.translator.TranslateRouteV2(ar.V2())
+ tctx, err = c.translator.TranslateRouteV2(ar.V2())
}
} else {
- tctx, err = c.controller.translator.TranslateRouteV2NotStrictly(ar.V2())
+ tctx, err = c.translator.TranslateRouteV2NotStrictly(ar.V2())
}
if err != nil {
log.Errorw("failed to translate ApisixRoute v2",
@@ -299,6 +322,12 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
)
return err
}
+ default:
+ log.Errorw("unknown ApisixRoute version",
+ zap.String("version", obj.GroupVersion),
+ zap.String("key", obj.Key),
+ )
+ return fmt.Errorf("unknown ApisixRoute version %v", obj.GroupVersion)
}
log.Debugw("translated ApisixRoute",
@@ -326,7 +355,7 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
} else if ev.Type == types.EventAdd {
added = m
} else {
- oldCtx, _ := c.controller.translator.TranslateOldRoute(obj.OldObject)
+ oldCtx, _ := c.translator.TranslateOldRoute(obj.OldObject)
om := &utils.Manifest{
Routes: oldCtx.Routes,
Upstreams: oldCtx.Upstreams,
@@ -336,13 +365,13 @@ func (c *apisixRouteController) sync(ctx context.Context, ev *types.Event) error
added, updated, deleted = m.Diff(om)
}
- return c.controller.syncManifests(ctx, added, updated, deleted)
+ return c.SyncManifests(ctx, added, updated, deleted)
}
func (c *apisixRouteController) checkPluginNameIfNotEmptyV2beta3(ctx context.Context, in *v2beta3.ApisixRoute) error {
for _, v := range in.Spec.HTTP {
if v.PluginConfigName != "" {
- _, err := c.controller.apisix.Cluster(c.controller.cfg.APISIX.DefaultClusterName).PluginConfig().Get(ctx, apisixv1.ComposePluginConfigName(in.Namespace, v.PluginConfigName))
+ _, err := c.APISIX.Cluster(c.Config.APISIX.DefaultClusterName).PluginConfig().Get(ctx, apisixv1.ComposePluginConfigName(in.Namespace, v.PluginConfigName))
if err != nil {
if err == apisixcache.ErrNotFound {
log.Errorw("checkPluginNameIfNotEmptyV2beta3 error: plugin_config not found",
@@ -365,7 +394,7 @@ func (c *apisixRouteController) checkPluginNameIfNotEmptyV2beta3(ctx context.Con
func (c *apisixRouteController) checkPluginNameIfNotEmptyV2(ctx context.Context, in *v2.ApisixRoute) error {
for _, v := range in.Spec.HTTP {
if v.PluginConfigName != "" {
- _, err := c.controller.apisix.Cluster(c.controller.cfg.APISIX.DefaultClusterName).PluginConfig().Get(ctx, apisixv1.ComposePluginConfigName(in.Namespace, v.PluginConfigName))
+ _, err := c.APISIX.Cluster(c.Config.APISIX.DefaultClusterName).PluginConfig().Get(ctx, apisixv1.ComposePluginConfigName(in.Namespace, v.PluginConfigName))
if err != nil {
if err == apisixcache.ErrNotFound {
log.Errorw("checkPluginNameIfNotEmptyV2 error: plugin_config not found",
@@ -399,31 +428,36 @@ func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin error)
namespace, name, errLocal := cache.SplitMetaNamespaceKey(event.Key)
if errLocal != nil {
log.Errorf("invalid resource key: %s", event.Key)
- c.controller.MetricsCollector.IncrSyncOperation("route", "failure")
+ c.MetricsCollector.IncrSyncOperation("route", "failure")
return
}
var ar kube.ApisixRoute
switch event.GroupVersion {
case config.ApisixV2beta2:
- ar, errLocal = c.controller.apisixRouteLister.V2beta2(namespace, name)
+ ar, errLocal = c.apisixRouteLister.V2beta2(namespace, name)
case config.ApisixV2beta3:
- ar, errLocal = c.controller.apisixRouteLister.V2beta3(namespace, name)
+ ar, errLocal = c.apisixRouteLister.V2beta3(namespace, name)
case config.ApisixV2:
- ar, errLocal = c.controller.apisixRouteLister.V2(namespace, name)
+ ar, errLocal = c.apisixRouteLister.V2(namespace, name)
+ default:
+ log.Errorw("unknown ApisixRoute version",
+ zap.String("version", event.GroupVersion),
+ zap.String("key", event.Key),
+ )
}
if errOrigin == nil {
if ev.Type != types.EventDelete {
if errLocal == nil {
switch ar.GroupVersion() {
case config.ApisixV2beta2:
- c.controller.recorderEvent(ar.V2beta2(), v1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(ar.V2beta2(), _resourceSynced, nil, metav1.ConditionTrue, ar.V2beta2().GetGeneration())
+ c.RecordEvent(ar.V2beta2(), v1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(ar.V2beta2(), utils.ResourceSynced, nil, metav1.ConditionTrue, ar.V2beta2().GetGeneration())
case config.ApisixV2beta3:
- c.controller.recorderEvent(ar.V2beta3(), v1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(ar.V2beta3(), _resourceSynced, nil, metav1.ConditionTrue, ar.V2beta3().GetGeneration())
+ c.RecordEvent(ar.V2beta3(), v1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(ar.V2beta3(), utils.ResourceSynced, nil, metav1.ConditionTrue, ar.V2beta3().GetGeneration())
case config.ApisixV2:
- c.controller.recorderEvent(ar.V2(), v1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(ar.V2(), _resourceSynced, nil, metav1.ConditionTrue, ar.V2().GetGeneration())
+ c.RecordEvent(ar.V2(), v1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(ar.V2(), utils.ResourceSynced, nil, metav1.ConditionTrue, ar.V2().GetGeneration())
}
} else {
log.Errorw("failed list ApisixRoute",
@@ -434,7 +468,7 @@ func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin error)
}
}
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("route", "success")
+ c.MetricsCollector.IncrSyncOperation("route", "success")
return
}
log.Warnw("sync ApisixRoute failed, will retry",
@@ -444,14 +478,14 @@ func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin error)
if errLocal == nil {
switch ar.GroupVersion() {
case config.ApisixV2beta2:
- c.controller.recorderEvent(ar.V2beta2(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
- c.controller.recordStatus(ar.V2beta2(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2beta2().GetGeneration())
+ c.RecordEvent(ar.V2beta2(), v1.EventTypeWarning, utils.ResourceSyncAborted, errOrigin)
+ c.recordStatus(ar.V2beta2(), utils.ResourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2beta2().GetGeneration())
case config.ApisixV2beta3:
- c.controller.recorderEvent(ar.V2beta3(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
- c.controller.recordStatus(ar.V2beta3(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2beta3().GetGeneration())
+ c.RecordEvent(ar.V2beta3(), v1.EventTypeWarning, utils.ResourceSyncAborted, errOrigin)
+ c.recordStatus(ar.V2beta3(), utils.ResourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2beta3().GetGeneration())
case config.ApisixV2:
- c.controller.recorderEvent(ar.V2(), v1.EventTypeWarning, _resourceSyncAborted, errOrigin)
- c.controller.recordStatus(ar.V2(), _resourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2().GetGeneration())
+ c.RecordEvent(ar.V2(), v1.EventTypeWarning, utils.ResourceSyncAborted, errOrigin)
+ c.recordStatus(ar.V2(), utils.ResourceSyncAborted, errOrigin, metav1.ConditionFalse, ar.V2().GetGeneration())
}
} else {
log.Errorw("failed list ApisixRoute",
@@ -461,7 +495,7 @@ func (c *apisixRouteController) handleSyncErr(obj interface{}, errOrigin error)
)
}
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("route", "failure")
+ c.MetricsCollector.IncrSyncOperation("route", "failure")
}
func (c *apisixRouteController) onAdd(obj interface{}) {
@@ -470,7 +504,7 @@ func (c *apisixRouteController) onAdd(obj interface{}) {
log.Errorf("found ApisixRoute resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixRoute add event arrived",
@@ -487,7 +521,7 @@ func (c *apisixRouteController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("route", "add")
+ c.MetricsCollector.IncrEvents("route", "add")
}
func (c *apisixRouteController) onUpdate(oldObj, newObj interface{}) {
@@ -501,7 +535,7 @@ func (c *apisixRouteController) onUpdate(oldObj, newObj interface{}) {
log.Errorf("found ApisixRoute resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixRoute update event arrived",
@@ -518,7 +552,7 @@ func (c *apisixRouteController) onUpdate(oldObj, newObj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("route", "update")
+ c.MetricsCollector.IncrEvents("route", "update")
}
func (c *apisixRouteController) onDelete(obj interface{}) {
@@ -535,7 +569,7 @@ func (c *apisixRouteController) onDelete(obj interface{}) {
log.Errorf("found ApisixRoute resource with bad meta namesapce key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixRoute delete event arrived",
@@ -551,11 +585,11 @@ func (c *apisixRouteController) onDelete(obj interface{}) {
Tombstone: ar,
})
- c.controller.MetricsCollector.IncrEvents("route", "delete")
+ c.MetricsCollector.IncrEvents("route", "delete")
}
func (c *apisixRouteController) ResourceSync() {
- objs := c.controller.apisixRouteInformer.GetIndexer().List()
+ objs := c.apisixRouteInformer.GetIndexer().List()
c.svcLock.Lock()
defer c.svcLock.Unlock()
@@ -570,7 +604,7 @@ func (c *apisixRouteController) ResourceSync() {
)
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
ar := kube.MustNewApisixRoute(obj)
@@ -605,6 +639,11 @@ func (c *apisixRouteController) ResourceSync() {
backends = append(backends, ns+"/"+backend.ServiceName)
}
}
+ default:
+ log.Errorw("unknown ApisixRoute version",
+ zap.String("version", ar.GroupVersion()),
+ zap.String("key", key),
+ )
}
for _, svcKey := range backends {
if _, ok := c.svcMap[svcKey]; !ok {
@@ -627,7 +666,7 @@ func (c *apisixRouteController) onSvcAdd(obj interface{}) {
)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
@@ -654,7 +693,7 @@ func (c *apisixRouteController) handleSvcAdd(key string) error {
Type: types.EventAdd,
Object: kube.ApisixRouteEvent{
Key: ns + "/" + route,
- GroupVersion: c.controller.cfg.Kubernetes.ApisixRouteVersion,
+ GroupVersion: c.Kubernetes.APIVersion,
},
})
}
@@ -675,3 +714,81 @@ func (c *apisixRouteController) handleSvcErr(key string, errOrigin error) {
)
c.workqueue.AddRateLimited(key)
}
+
+// recordStatus record resources status
+func (c *apisixRouteController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2beta2.ApisixRoute:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta2().ApisixRoutes(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixRoute",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ case *v2beta3.ApisixRoute:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta3().ApisixRoutes(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixRoute",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ case *v2.ApisixRoute:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2().ApisixRoutes(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixRoute",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/ingress/apisix_tls.go b/pkg/providers/apisix/apisix_tls.go
similarity index 61%
rename from pkg/ingress/apisix_tls.go
rename to pkg/providers/apisix/apisix_tls.go
index be484edc..d2b55225 100644
--- a/pkg/ingress/apisix_tls.go
+++ b/pkg/providers/apisix/apisix_tls.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
@@ -23,37 +23,60 @@ import (
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"github.com/apache/apisix-ingress-controller/pkg/config"
"github.com/apache/apisix-ingress-controller/pkg/kube"
+ 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"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
type apisixTlsController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *apisixCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ secretInformer cache.SharedIndexInformer
+ apisixTlsLister kube.ApisixTlsLister
+ apisixTlsInformer cache.SharedIndexInformer
+
+ // this map enrolls which ApisixTls objects refer to a Kubernetes
+ // Secret object.
+ // type: Map<SecretKey, Map<ApisixTlsKey, ApisixTls>>
+ // SecretKey is `namespace_name`, ApisixTlsKey is kube style meta key: `namespace/name`
+ secretSSLMap *sync.Map
}
-func (c *Controller) newApisixTlsController() *apisixTlsController {
- ctl := &apisixTlsController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixTls"),
- workers: 1,
+func newApisixTlsController(common *apisixCommon) *apisixTlsController {
+ c := &apisixTlsController{
+ apisixCommon: common,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixTls"),
+ workers: 1,
+
+ secretInformer: common.SecretInformer,
+ apisixTlsLister: common.ApisixTlsLister,
+ apisixTlsInformer: common.ApisixTlsInformer,
+
+ secretSSLMap: new(sync.Map),
}
- ctl.controller.apisixTlsInformer.AddEventHandler(
+
+ c.apisixTlsInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
- return ctl
+ return c
}
func (c *apisixTlsController) run(ctx context.Context) {
@@ -61,7 +84,7 @@ func (c *apisixTlsController) run(ctx context.Context) {
defer log.Info("ApisixTls controller exited")
defer c.workqueue.ShutDown()
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.apisixTlsInformer.HasSynced, c.controller.secretInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.apisixTlsInformer.HasSynced, c.secretInformer.HasSynced); !ok {
log.Errorf("informers sync failed")
return
}
@@ -96,9 +119,9 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error {
var multiVersionedTls kube.ApisixTls
switch event.GroupVersion {
case config.ApisixV2beta3:
- multiVersionedTls, err = c.controller.apisixTlsLister.V2beta3(namespace, name)
+ multiVersionedTls, err = c.apisixTlsLister.V2beta3(namespace, name)
case config.ApisixV2:
- multiVersionedTls, err = c.controller.apisixTlsLister.V2(namespace, name)
+ multiVersionedTls, err = c.apisixTlsLister.V2(namespace, name)
default:
return fmt.Errorf("unsupported ApisixTls group version %s", event.GroupVersion)
}
@@ -135,14 +158,14 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error {
switch event.GroupVersion {
case config.ApisixV2beta3:
tls := multiVersionedTls.V2beta3()
- ssl, err := c.controller.translator.TranslateSSLV2Beta3(tls)
+ ssl, err := c.translator.TranslateSSLV2Beta3(tls)
if err != nil {
log.Errorw("failed to translate ApisixTls",
zap.Error(err),
zap.Any("ApisixTls", tls),
)
- c.controller.recorderEvent(tls, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
+ c.RecordEvent(tls, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(tls, utils.ResourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
return err
}
log.Debugw("got SSL object from ApisixTls",
@@ -159,28 +182,28 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error {
}
}
- if err := c.controller.syncSSL(ctx, ssl, ev.Type); err != nil {
+ if err := c.SyncSSL(ctx, ssl, ev.Type); err != nil {
log.Errorw("failed to sync SSL to APISIX",
zap.Error(err),
zap.Any("ssl", ssl),
)
- c.controller.recorderEvent(tls, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
+ c.RecordEvent(tls, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(tls, utils.ResourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
return err
}
- c.controller.recorderEvent(tls, corev1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(tls, _resourceSynced, nil, metav1.ConditionTrue, tls.GetGeneration())
+ c.RecordEvent(tls, corev1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(tls, utils.ResourceSynced, nil, metav1.ConditionTrue, tls.GetGeneration())
return err
case config.ApisixV2:
tls := multiVersionedTls.V2()
- ssl, err := c.controller.translator.TranslateSSLV2(tls)
+ ssl, err := c.translator.TranslateSSLV2(tls)
if err != nil {
log.Errorw("failed to translate ApisixTls",
zap.Error(err),
zap.Any("ApisixTls", tls),
)
- c.controller.recorderEvent(tls, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
+ c.RecordEvent(tls, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(tls, utils.ResourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
return err
}
log.Debugw("got SSL object from ApisixTls",
@@ -197,17 +220,17 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error {
}
}
- if err := c.controller.syncSSL(ctx, ssl, ev.Type); err != nil {
+ if err := c.SyncSSL(ctx, ssl, ev.Type); err != nil {
log.Errorw("failed to sync SSL to APISIX",
zap.Error(err),
zap.Any("ssl", ssl),
)
- c.controller.recorderEvent(tls, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(tls, _resourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
+ c.RecordEvent(tls, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(tls, utils.ResourceSyncAborted, err, metav1.ConditionFalse, tls.GetGeneration())
return err
}
- c.controller.recorderEvent(tls, corev1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(tls, _resourceSynced, nil, metav1.ConditionTrue, tls.GetGeneration())
+ c.RecordEvent(tls, corev1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(tls, utils.ResourceSynced, nil, metav1.ConditionTrue, tls.GetGeneration())
return err
default:
return fmt.Errorf("unsupported ApisixTls group version %s", event.GroupVersion)
@@ -215,27 +238,27 @@ func (c *apisixTlsController) sync(ctx context.Context, ev *types.Event) error {
}
func (c *apisixTlsController) syncSecretSSL(secretKey string, apisixTlsKey string, ssl *v1.Ssl, event types.EventType) {
- if ssls, ok := c.controller.secretSSLMap.Load(secretKey); ok {
+ if ssls, ok := c.secretSSLMap.Load(secretKey); ok {
sslMap := ssls.(*sync.Map)
switch event {
case types.EventDelete:
sslMap.Delete(apisixTlsKey)
- c.controller.secretSSLMap.Store(secretKey, sslMap)
+ c.secretSSLMap.Store(secretKey, sslMap)
default:
sslMap.Store(apisixTlsKey, ssl)
- c.controller.secretSSLMap.Store(secretKey, sslMap)
+ c.secretSSLMap.Store(secretKey, sslMap)
}
} else if event != types.EventDelete {
sslMap := new(sync.Map)
sslMap.Store(apisixTlsKey, ssl)
- c.controller.secretSSLMap.Store(secretKey, sslMap)
+ c.secretSSLMap.Store(secretKey, sslMap)
}
}
func (c *apisixTlsController) handleSyncErr(obj interface{}, err error) {
if err == nil {
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("TLS", "success")
+ c.MetricsCollector.IncrSyncOperation("TLS", "success")
return
}
@@ -255,7 +278,7 @@ func (c *apisixTlsController) handleSyncErr(obj interface{}, err error) {
zap.Error(err),
)
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("TLS", "failure")
+ c.MetricsCollector.IncrSyncOperation("TLS", "failure")
}
func (c *apisixTlsController) onAdd(obj interface{}) {
@@ -269,7 +292,7 @@ func (c *apisixTlsController) onAdd(obj interface{}) {
log.Errorf("found ApisixTls object with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixTls add event arrived",
@@ -283,7 +306,7 @@ func (c *apisixTlsController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("TLS", "add")
+ c.MetricsCollector.IncrEvents("TLS", "add")
}
func (c *apisixTlsController) onUpdate(prev, curr interface{}) {
@@ -305,7 +328,7 @@ func (c *apisixTlsController) onUpdate(prev, curr interface{}) {
log.Errorf("found ApisixTls object with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixTls update event arrived",
@@ -321,7 +344,7 @@ func (c *apisixTlsController) onUpdate(prev, curr interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("TLS", "update")
+ c.MetricsCollector.IncrEvents("TLS", "update")
}
func (c *apisixTlsController) onDelete(obj interface{}) {
@@ -342,7 +365,7 @@ func (c *apisixTlsController) onDelete(obj interface{}) {
log.Errorf("found ApisixTls resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixTls delete event arrived",
@@ -357,18 +380,18 @@ func (c *apisixTlsController) onDelete(obj interface{}) {
Tombstone: tls,
})
- c.controller.MetricsCollector.IncrEvents("TLS", "delete")
+ c.MetricsCollector.IncrEvents("TLS", "delete")
}
func (c *apisixTlsController) ResourceSync() {
- objs := c.controller.apisixTlsInformer.GetIndexer().List()
+ objs := c.apisixTlsInformer.GetIndexer().List()
for _, obj := range objs {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
log.Errorw("ApisixTls sync failed, found ApisixTls object with bad namespace/name ignore it", zap.String("error", err.Error()))
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
tls, err := kube.NewApisixTls(obj)
@@ -385,3 +408,64 @@ func (c *apisixTlsController) ResourceSync() {
})
}
}
+
+// recordStatus record resources status
+func (c *apisixTlsController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2beta3.ApisixTls:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta3().ApisixTlses(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixTls",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ case *configv2.ApisixTls:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2().ApisixTlses(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixTls",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/ingress/apisix_upstream.go b/pkg/providers/apisix/apisix_upstream.go
similarity index 64%
rename from pkg/ingress/apisix_upstream.go
rename to pkg/providers/apisix/apisix_upstream.go
index 526ba977..ff9d0678 100644
--- a/pkg/ingress/apisix_upstream.go
+++ b/pkg/providers/apisix/apisix_upstream.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
@@ -22,7 +22,10 @@ import (
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ listerscorev1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
@@ -32,30 +35,43 @@ import (
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"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
type apisixUpstreamController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *apisixCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ svcInformer cache.SharedIndexInformer
+ svcLister listerscorev1.ServiceLister
+ apisixUpstreamInformer cache.SharedIndexInformer
+ apisixUpstreamLister kube.ApisixUpstreamLister
}
-func (c *Controller) newApisixUpstreamController() *apisixUpstreamController {
- ctl := &apisixUpstreamController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixUpstream"),
- workers: 1,
+func newApisixUpstreamController(common *apisixCommon) *apisixUpstreamController {
+ c := &apisixUpstreamController{
+ apisixCommon: common,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ApisixUpstream"),
+ workers: 1,
+
+ svcInformer: common.SvcInformer,
+ svcLister: common.SvcLister,
+ apisixUpstreamLister: common.ApisixUpstreamLister,
+ apisixUpstreamInformer: common.ApisixUpstreamInformer,
}
- ctl.controller.apisixUpstreamInformer.AddEventHandler(
+
+ c.apisixUpstreamInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
- return ctl
+ return c
}
func (c *apisixUpstreamController) run(ctx context.Context) {
@@ -63,7 +79,7 @@ func (c *apisixUpstreamController) run(ctx context.Context) {
defer log.Info("ApisixUpstream controller exited")
defer c.workqueue.ShutDown()
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.apisixUpstreamInformer.HasSynced, c.controller.svcInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.apisixUpstreamInformer.HasSynced, c.svcInformer.HasSynced); !ok {
log.Error("cache sync failed")
return
}
@@ -102,9 +118,9 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
var multiVersioned kube.ApisixUpstream
switch event.GroupVersion {
case config.ApisixV2beta3:
- multiVersioned, err = c.controller.apisixUpstreamLister.V2beta3(namespace, name)
+ multiVersioned, err = c.apisixUpstreamLister.V2beta3(namespace, name)
case config.ApisixV2:
- multiVersioned, err = c.controller.apisixUpstreamLister.V2(namespace, name)
+ multiVersioned, err = c.apisixUpstreamLister.V2(namespace, name)
default:
return fmt.Errorf("unsupported ApisixUpstream group version %s", event.GroupVersion)
}
@@ -150,11 +166,11 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
}
}
- svc, err := c.controller.svcLister.Services(namespace).Get(name)
+ svc, err := c.svcLister.Services(namespace).Get(name)
if err != nil {
log.Errorf("failed to get service %s: %s", key, err)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
@@ -163,19 +179,19 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
if au.Spec != nil && len(au.Spec.Subsets) > 0 {
subsets = append(subsets, au.Spec.Subsets...)
}
- clusterName := c.controller.cfg.APISIX.DefaultClusterName
+ clusterName := c.Config.APISIX.DefaultClusterName
for _, port := range svc.Spec.Ports {
for _, subset := range subsets {
upsName := apisixv1.ComposeUpstreamName(namespace, name, subset.Name, port.Port)
// TODO: multiple cluster
- ups, err := c.controller.apisix.Cluster(clusterName).Upstream().Get(ctx, upsName)
+ ups, err := c.APISIX.Cluster(clusterName).Upstream().Get(ctx, upsName)
if err != nil {
if err == apisixcache.ErrNotFound {
continue
}
log.Errorf("failed to get upstream %s: %s", upsName, err)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
var newUps *apisixv1.Upstream
@@ -185,14 +201,14 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
cfg = &au.Spec.ApisixUpstreamConfig
}
// FIXME Same ApisixUpstreamConfig might be translated multiple times.
- newUps, err = c.controller.translator.TranslateUpstreamConfigV2beta3(cfg)
+ newUps, err = c.translator.TranslateUpstreamConfigV2beta3(cfg)
if err != nil {
log.Errorw("found malformed ApisixUpstream",
zap.Any("object", au),
zap.Error(err),
)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
} else {
@@ -206,22 +222,22 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
zap.Any("upstream", newUps),
zap.Any("ApisixUpstream", au),
)
- if _, err := c.controller.apisix.Cluster(clusterName).Upstream().Update(ctx, newUps); err != nil {
+ if _, err := c.APISIX.Cluster(clusterName).Upstream().Update(ctx, newUps); err != nil {
log.Errorw("failed to update upstream",
zap.Error(err),
zap.Any("upstream", newUps),
zap.Any("ApisixUpstream", au),
zap.String("cluster", clusterName),
)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
}
}
if ev.Type != types.EventDelete {
- c.controller.recorderEvent(au, corev1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(au, _resourceSynced, nil, metav1.ConditionTrue, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(au, utils.ResourceSynced, nil, metav1.ConditionTrue, au.GetGeneration())
}
case config.ApisixV2:
au := multiVersioned.V2()
@@ -234,11 +250,11 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
}
}
- svc, err := c.controller.svcLister.Services(namespace).Get(name)
+ svc, err := c.svcLister.Services(namespace).Get(name)
if err != nil {
log.Errorf("failed to get service %s: %s", key, err)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
@@ -247,19 +263,19 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
if au.Spec != nil && len(au.Spec.Subsets) > 0 {
subsets = append(subsets, au.Spec.Subsets...)
}
- clusterName := c.controller.cfg.APISIX.DefaultClusterName
+ clusterName := c.Config.APISIX.DefaultClusterName
for _, port := range svc.Spec.Ports {
for _, subset := range subsets {
upsName := apisixv1.ComposeUpstreamName(namespace, name, subset.Name, port.Port)
// TODO: multiple cluster
- ups, err := c.controller.apisix.Cluster(clusterName).Upstream().Get(ctx, upsName)
+ ups, err := c.APISIX.Cluster(clusterName).Upstream().Get(ctx, upsName)
if err != nil {
if err == apisixcache.ErrNotFound {
continue
}
log.Errorf("failed to get upstream %s: %s", upsName, err)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
var newUps *apisixv1.Upstream
@@ -269,14 +285,14 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
cfg = &au.Spec.ApisixUpstreamConfig
}
// FIXME Same ApisixUpstreamConfig might be translated multiple times.
- newUps, err = c.controller.translator.TranslateUpstreamConfigV2(cfg)
+ newUps, err = c.translator.TranslateUpstreamConfigV2(cfg)
if err != nil {
log.Errorw("found malformed ApisixUpstream",
zap.Any("object", au),
zap.Error(err),
)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
} else {
@@ -290,22 +306,22 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
zap.Any("upstream", newUps),
zap.Any("ApisixUpstream", au),
)
- if _, err := c.controller.apisix.Cluster(clusterName).Upstream().Update(ctx, newUps); err != nil {
+ if _, err := c.APISIX.Cluster(clusterName).Upstream().Update(ctx, newUps); err != nil {
log.Errorw("failed to update upstream",
zap.Error(err),
zap.Any("upstream", newUps),
zap.Any("ApisixUpstream", au),
zap.String("cluster", clusterName),
)
- c.controller.recorderEvent(au, corev1.EventTypeWarning, _resourceSyncAborted, err)
- c.controller.recordStatus(au, _resourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeWarning, utils.ResourceSyncAborted, err)
+ c.recordStatus(au, utils.ResourceSyncAborted, err, metav1.ConditionFalse, au.GetGeneration())
return err
}
}
}
if ev.Type != types.EventDelete {
- c.controller.recorderEvent(au, corev1.EventTypeNormal, _resourceSynced, nil)
- c.controller.recordStatus(au, _resourceSynced, nil, metav1.ConditionTrue, au.GetGeneration())
+ c.RecordEvent(au, corev1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(au, utils.ResourceSynced, nil, metav1.ConditionTrue, au.GetGeneration())
}
}
@@ -315,7 +331,7 @@ func (c *apisixUpstreamController) sync(ctx context.Context, ev *types.Event) er
func (c *apisixUpstreamController) handleSyncErr(obj interface{}, err error) {
if err == nil {
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("upstream", "success")
+ c.MetricsCollector.IncrSyncOperation("upstream", "success")
return
}
@@ -333,7 +349,7 @@ func (c *apisixUpstreamController) handleSyncErr(obj interface{}, err error) {
zap.Error(err),
)
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("upstream", "failure")
+ c.MetricsCollector.IncrSyncOperation("upstream", "failure")
}
func (c *apisixUpstreamController) onAdd(obj interface{}) {
@@ -348,7 +364,7 @@ func (c *apisixUpstreamController) onAdd(obj interface{}) {
log.Errorf("found ApisixUpstream resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixUpstream add event arrived",
@@ -362,7 +378,7 @@ func (c *apisixUpstreamController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("upstream", "add")
+ c.MetricsCollector.IncrEvents("upstream", "add")
}
func (c *apisixUpstreamController) onUpdate(oldObj, newObj interface{}) {
@@ -384,7 +400,7 @@ func (c *apisixUpstreamController) onUpdate(oldObj, newObj interface{}) {
log.Errorf("found ApisixUpstream resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixUpstream update event arrived",
@@ -401,7 +417,7 @@ func (c *apisixUpstreamController) onUpdate(oldObj, newObj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("upstream", "update")
+ c.MetricsCollector.IncrEvents("upstream", "update")
}
func (c *apisixUpstreamController) onDelete(obj interface{}) {
@@ -423,7 +439,7 @@ func (c *apisixUpstreamController) onDelete(obj interface{}) {
log.Errorf("found ApisixUpstream resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("ApisixUpstream delete event arrived",
@@ -438,18 +454,18 @@ func (c *apisixUpstreamController) onDelete(obj interface{}) {
Tombstone: au,
})
- c.controller.MetricsCollector.IncrEvents("upstream", "delete")
+ c.MetricsCollector.IncrEvents("upstream", "delete")
}
func (c *apisixUpstreamController) ResourceSync() {
- objs := c.controller.apisixUpstreamInformer.GetIndexer().List()
+ objs := c.apisixUpstreamInformer.GetIndexer().List()
for _, obj := range objs {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
log.Errorw("ApisixUpstream sync failed, found ApisixUpstream resource with bad meta namespace key", zap.String("error", err.Error()))
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
au, err := kube.NewApisixUpstream(obj)
@@ -466,3 +482,65 @@ func (c *apisixUpstreamController) ResourceSync() {
})
}
}
+
+// recordStatus record resources status
+func (c *apisixUpstreamController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2beta3.ApisixUpstream:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2beta3().ApisixUpstreams(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixUpstream",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+
+ case *configv2.ApisixUpstream:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord := apisixClient.ApisixV2().ApisixUpstreams(v.Namespace).
+ UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for ApisixUpstream",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/providers/apisix/provider.go b/pkg/providers/apisix/provider.go
new file mode 100644
index 00000000..21baa66d
--- /dev/null
+++ b/pkg/providers/apisix/provider.go
@@ -0,0 +1,202 @@
+// 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 apisix
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "k8s.io/client-go/tools/cache"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ apisixtranslation "github.com/apache/apisix-ingress-controller/pkg/providers/apisix/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
+)
+
+const (
+ ProviderName = "APISIX"
+)
+
+type apisixCommon struct {
+ *providertypes.Common
+
+ namespaceProvider namespace.WatchingNamespaceProvider
+ translator apisixtranslation.ApisixTranslator
+}
+
+var _ Provider = (*apisixProvider)(nil)
+
+type Provider interface {
+ providertypes.Provider
+
+ Init(ctx context.Context) error
+ ResourceSync()
+
+ GetSslFromSecretKey(string) *sync.Map
+}
+
+type apisixProvider struct {
+ name string
+ common *providertypes.Common
+ namespaceProvider namespace.WatchingNamespaceProvider
+
+ apisixTranslator apisixtranslation.ApisixTranslator
+ apisixUpstreamController *apisixUpstreamController
+ apisixRouteController *apisixRouteController
+ apisixTlsController *apisixTlsController
+ apisixClusterConfigController *apisixClusterConfigController
+ apisixConsumerController *apisixConsumerController
+ apisixPluginConfigController *apisixPluginConfigController
+
+ apisixRouteInformer cache.SharedIndexInformer
+ apisixClusterConfigInformer cache.SharedIndexInformer
+ apisixConsumerInformer cache.SharedIndexInformer
+ apisixPluginConfigInformer cache.SharedIndexInformer
+}
+
+func NewProvider(common *providertypes.Common, namespaceProvider namespace.WatchingNamespaceProvider,
+ translator translation.Translator) (Provider, apisixtranslation.ApisixTranslator, error) {
+ p := &apisixProvider{
+ name: ProviderName,
+ common: common,
+ namespaceProvider: namespaceProvider,
+ }
+
+ apisixFactory := common.KubeClient.NewAPISIXSharedIndexInformerFactory()
+
+ p.apisixTranslator = apisixtranslation.NewApisixTranslator(&apisixtranslation.TranslatorOptions{
+ Apisix: common.APISIX,
+ ClusterName: common.Config.APISIX.DefaultClusterName,
+ ServiceLister: common.SvcLister,
+ SecretLister: common.SecretLister,
+ }, translator)
+ c := &apisixCommon{
+ Common: common,
+ namespaceProvider: namespaceProvider,
+ translator: p.apisixTranslator,
+ }
+
+ switch c.Config.Kubernetes.APIVersion {
+ case config.ApisixV2beta3:
+ p.apisixRouteInformer = apisixFactory.Apisix().V2beta3().ApisixRoutes().Informer()
+ p.apisixClusterConfigInformer = apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Informer()
+ p.apisixConsumerInformer = apisixFactory.Apisix().V2beta3().ApisixConsumers().Informer()
+ p.apisixPluginConfigInformer = apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Informer()
+
+ case config.ApisixV2:
+ p.apisixRouteInformer = apisixFactory.Apisix().V2().ApisixRoutes().Informer()
+ p.apisixClusterConfigInformer = apisixFactory.Apisix().V2().ApisixClusterConfigs().Informer()
+ p.apisixConsumerInformer = apisixFactory.Apisix().V2().ApisixConsumers().Informer()
+ p.apisixPluginConfigInformer = apisixFactory.Apisix().V2().ApisixPluginConfigs().Informer()
+ default:
+ panic(fmt.Errorf("unsupported API version %v", c.Config.Kubernetes.APIVersion))
+ }
+
+ apisixRouteLister := kube.NewApisixRouteLister(
+ apisixFactory.Apisix().V2beta2().ApisixRoutes().Lister(),
+ apisixFactory.Apisix().V2beta3().ApisixRoutes().Lister(),
+ apisixFactory.Apisix().V2().ApisixRoutes().Lister(),
+ )
+ apisixClusterConfigLister := kube.NewApisixClusterConfigLister(
+ apisixFactory.Apisix().V2beta3().ApisixClusterConfigs().Lister(),
+ apisixFactory.Apisix().V2().ApisixClusterConfigs().Lister(),
+ )
+ apisixConsumerLister := kube.NewApisixConsumerLister(
+ apisixFactory.Apisix().V2beta3().ApisixConsumers().Lister(),
+ apisixFactory.Apisix().V2().ApisixConsumers().Lister(),
+ )
+ apisixPluginConfigLister := kube.NewApisixPluginConfigLister(
+ apisixFactory.Apisix().V2beta3().ApisixPluginConfigs().Lister(),
+ apisixFactory.Apisix().V2().ApisixPluginConfigs().Lister(),
+ )
+
+ p.apisixUpstreamController = newApisixUpstreamController(c)
+ p.apisixRouteController = newApisixRouteController(c, p.apisixRouteInformer, apisixRouteLister)
+ p.apisixTlsController = newApisixTlsController(c)
+ p.apisixClusterConfigController = newApisixClusterConfigController(c, p.apisixClusterConfigInformer, apisixClusterConfigLister)
+ p.apisixConsumerController = newApisixConsumerController(c, p.apisixConsumerInformer, apisixConsumerLister)
+ p.apisixPluginConfigController = newApisixPluginConfigController(c, p.apisixPluginConfigInformer, apisixPluginConfigLister)
+
+ return p, p.apisixTranslator, nil
+}
+
+func (p *apisixProvider) Run(ctx context.Context) {
+ e := utils.ParallelExecutor{}
+
+ e.Add(func() {
+ p.apisixRouteInformer.Run(ctx.Done())
+ })
+ e.Add(func() {
+ p.apisixClusterConfigInformer.Run(ctx.Done())
+ })
+ e.Add(func() {
+ p.apisixConsumerInformer.Run(ctx.Done())
+ })
+ e.Add(func() {
+ p.apisixPluginConfigInformer.Run(ctx.Done())
+ })
+
+ e.Add(func() {
+ p.apisixUpstreamController.run(ctx)
+ })
+ e.Add(func() {
+ p.apisixRouteController.run(ctx)
+ })
+ e.Add(func() {
+ p.apisixTlsController.run(ctx)
+ })
+ e.Add(func() {
+ p.apisixClusterConfigController.run(ctx)
+ })
+ e.Add(func() {
+ p.apisixConsumerController.run(ctx)
+ })
+ e.Add(func() {
+ p.apisixPluginConfigController.run(ctx)
+ })
+
+ e.Wait()
+}
+
+func (p *apisixProvider) ResourceSync() {
+ e := utils.ParallelExecutor{}
+
+ e.Add(p.apisixUpstreamController.ResourceSync)
+ e.Add(p.apisixRouteController.ResourceSync)
+ e.Add(p.apisixTlsController.ResourceSync)
+ e.Add(p.apisixClusterConfigController.ResourceSync)
+ e.Add(p.apisixConsumerController.ResourceSync)
+ e.Add(p.apisixPluginConfigController.ResourceSync)
+
+ e.Wait()
+}
+
+func (p *apisixProvider) GetSslFromSecretKey(secretMapKey string) *sync.Map {
+ ssls, ok := p.apisixTlsController.secretSSLMap.Load(secretMapKey)
+ if !ok {
+ // This secret is not concerned.
+ return nil
+ }
+ sslMap := ssls.(*sync.Map)
+ return sslMap
+}
diff --git a/pkg/ingress/compare.go b/pkg/providers/apisix/provider_init.go
similarity index 70%
rename from pkg/ingress/compare.go
rename to pkg/providers/apisix/provider_init.go
index e9117c68..bb6feef3 100644
--- a/pkg/ingress/compare.go
+++ b/pkg/providers/apisix/provider_init.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package apisix
import (
"context"
@@ -25,12 +25,12 @@ import (
"github.com/apache/apisix-ingress-controller/pkg/log"
)
-// CompareResources used to compare the object IDs in resources and APISIX
+// Init used to compare the object IDs in resources and APISIX
// Find out the rest of objects in APISIX
// AND warn them in log.
// This func is NOT concurrency safe.
// cc https://github.com/apache/apisix-ingress-controller/pull/742#discussion_r757197791
-func (c *Controller) CompareResources(ctx context.Context) error {
+func (p *apisixProvider) Init(ctx context.Context) error {
var (
wg sync.WaitGroup
routeMapK8S = new(sync.Map)
@@ -48,7 +48,7 @@ func (c *Controller) CompareResources(ctx context.Context) error {
pluginConfigMapA6 = make(map[string]string)
)
- namespaces := c.namespaceProvider.WatchingNamespaces()
+ namespaces := p.namespaceProvider.WatchingNamespaces()
for _, key := range namespaces {
log.Debugf("start to watch namespace: %s", key)
wg.Add(1)
@@ -56,15 +56,15 @@ func (c *Controller) CompareResources(ctx context.Context) error {
defer wg.Done()
// ApisixRoute
opts := v1.ListOptions{}
- switch c.cfg.Kubernetes.ApisixRouteVersion {
+ switch p.common.Config.Kubernetes.APIVersion {
case config.ApisixV2beta3:
- retRoutes, err := c.kubeClient.APISIXClient.ApisixV2beta3().ApisixRoutes(ns).List(ctx, opts)
+ retRoutes, err := p.common.KubeClient.APISIXClient.ApisixV2beta3().ApisixRoutes(ns).List(ctx, opts)
if err != nil {
log.Error(err.Error())
ctx.Done()
} else {
for _, r := range retRoutes.Items {
- tc, err := c.translator.TranslateRouteV2beta3NotStrictly(&r)
+ tc, err := p.apisixTranslator.TranslateRouteV2beta3NotStrictly(&r)
if err != nil {
log.Error(err.Error())
ctx.Done()
@@ -93,13 +93,13 @@ func (c *Controller) CompareResources(ctx context.Context) error {
}
}
case config.ApisixV2:
- retRoutes, err := c.kubeClient.APISIXClient.ApisixV2().ApisixRoutes(ns).List(ctx, opts)
+ retRoutes, err := p.common.KubeClient.APISIXClient.ApisixV2().ApisixRoutes(ns).List(ctx, opts)
if err != nil {
log.Error(err.Error())
ctx.Done()
} else {
for _, r := range retRoutes.Items {
- tc, err := c.translator.TranslateRouteV2NotStrictly(&r)
+ tc, err := p.apisixTranslator.TranslateRouteV2NotStrictly(&r)
if err != nil {
log.Error(err.Error())
ctx.Done()
@@ -129,22 +129,22 @@ func (c *Controller) CompareResources(ctx context.Context) error {
}
default:
log.Errorw("failed to sync ApisixRoute, unexpected version",
- zap.String("version", c.cfg.Kubernetes.ApisixRouteVersion),
+ zap.String("version", p.common.Config.Kubernetes.APIVersion),
)
}
// todo ApisixUpstream and ApisixPluginConfig
// ApisixUpstream and ApisixPluginConfig should be synced with ApisixRoute resource
- switch c.cfg.Kubernetes.APIVersion {
+ switch p.common.Config.Kubernetes.APIVersion {
case config.ApisixV2beta3:
// ApisixConsumer
- retConsumer, err := c.kubeClient.APISIXClient.ApisixV2beta3().ApisixConsumers(ns).List(ctx, opts)
+ retConsumer, err := p.common.KubeClient.APISIXClient.ApisixV2beta3().ApisixConsumers(ns).List(ctx, opts)
if err != nil {
log.Error(err.Error())
ctx.Done()
} else {
for _, con := range retConsumer.Items {
- consumer, err := c.translator.TranslateApisixConsumerV2beta3(&con)
+ consumer, err := p.apisixTranslator.TranslateApisixConsumerV2beta3(&con)
if err != nil {
log.Error(err.Error())
ctx.Done()
@@ -154,13 +154,13 @@ func (c *Controller) CompareResources(ctx context.Context) error {
}
}
// ApisixTls
- retSSL, err := c.kubeClient.APISIXClient.ApisixV2beta3().ApisixTlses(ns).List(ctx, opts)
+ retSSL, err := p.common.KubeClient.APISIXClient.ApisixV2beta3().ApisixTlses(ns).List(ctx, opts)
if err != nil {
log.Error(err.Error())
ctx.Done()
} else {
for _, s := range retSSL.Items {
- ssl, err := c.translator.TranslateSSLV2Beta3(&s)
+ ssl, err := p.apisixTranslator.TranslateSSLV2Beta3(&s)
if err != nil {
log.Error(err.Error())
ctx.Done()
@@ -171,13 +171,13 @@ func (c *Controller) CompareResources(ctx context.Context) error {
}
case config.ApisixV2:
// ApisixConsumer
- retConsumer, err := c.kubeClient.APISIXClient.ApisixV2().ApisixConsumers(ns).List(ctx, opts)
+ retConsumer, err := p.common.KubeClient.APISIXClient.ApisixV2().ApisixConsumers(ns).List(ctx, opts)
if err != nil {
log.Error(err.Error())
ctx.Done()
} else {
for _, con := range retConsumer.Items {
- consumer, err := c.translator.TranslateApisixConsumerV2(&con)
+ consumer, err := p.apisixTranslator.TranslateApisixConsumerV2(&con)
if err != nil {
log.Error(err.Error())
ctx.Done()
@@ -187,13 +187,13 @@ func (c *Controller) CompareResources(ctx context.Context) error {
}
}
// ApisixTls
- retSSL, err := c.kubeClient.APISIXClient.ApisixV2().ApisixTlses(ns).List(ctx, opts)
+ retSSL, err := p.common.KubeClient.APISIXClient.ApisixV2().ApisixTlses(ns).List(ctx, opts)
if err != nil {
log.Error(err.Error())
ctx.Done()
} else {
for _, s := range retSSL.Items {
- ssl, err := c.translator.TranslateSSLV2(&s)
+ ssl, err := p.apisixTranslator.TranslateSSLV2(&s)
if err != nil {
log.Error(err.Error())
ctx.Done()
@@ -204,7 +204,7 @@ func (c *Controller) CompareResources(ctx context.Context) error {
}
default:
log.Errorw("failed to sync ApisixConsumer, unexpected version",
- zap.String("version", c.cfg.Kubernetes.APIVersion),
+ zap.String("version", p.common.Config.Kubernetes.APIVersion),
)
}
}(key)
@@ -212,22 +212,22 @@ func (c *Controller) CompareResources(ctx context.Context) error {
wg.Wait()
// 2.get all cache routes
- if err := c.listRouteCache(ctx, routeMapA6); err != nil {
+ if err := p.listRouteCache(ctx, routeMapA6); err != nil {
return err
}
- if err := c.listStreamRouteCache(ctx, streamRouteMapA6); err != nil {
+ if err := p.listStreamRouteCache(ctx, streamRouteMapA6); err != nil {
return err
}
- if err := c.listUpstreamCache(ctx, upstreamMapA6); err != nil {
+ if err := p.listUpstreamCache(ctx, upstreamMapA6); err != nil {
return err
}
- if err := c.listSSLCache(ctx, sslMapA6); err != nil {
+ if err := p.listSSLCache(ctx, sslMapA6); err != nil {
return err
}
- if err := c.listConsumerCache(ctx, consumerMapA6); err != nil {
+ if err := p.listConsumerCache(ctx, consumerMapA6); err != nil {
return err
}
- if err := c.listPluginConfigCache(ctx, pluginConfigMapA6); err != nil {
+ if err := p.listPluginConfigCache(ctx, pluginConfigMapA6); err != nil {
return err
}
// 3.compare
@@ -267,8 +267,8 @@ func findRedundant(src map[string]string, dest *sync.Map) map[string]string {
return result
}
-func (c *Controller) listRouteCache(ctx context.Context, routeMapA6 map[string]string) error {
- routesInA6, err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).Route().List(ctx)
+func (p *apisixProvider) listRouteCache(ctx context.Context, routeMapA6 map[string]string) error {
+ routesInA6, err := p.common.APISIX.Cluster(p.common.Config.APISIX.DefaultClusterName).Route().List(ctx)
if err != nil {
return err
} else {
@@ -279,8 +279,8 @@ func (c *Controller) listRouteCache(ctx context.Context, routeMapA6 map[string]s
return nil
}
-func (c *Controller) listStreamRouteCache(ctx context.Context, streamRouteMapA6 map[string]string) error {
- streamRoutesInA6, err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).StreamRoute().List(ctx)
+func (p *apisixProvider) listStreamRouteCache(ctx context.Context, streamRouteMapA6 map[string]string) error {
+ streamRoutesInA6, err := p.common.APISIX.Cluster(p.common.Config.APISIX.DefaultClusterName).StreamRoute().List(ctx)
if err != nil {
return err
} else {
@@ -291,8 +291,8 @@ func (c *Controller) listStreamRouteCache(ctx context.Context, streamRouteMapA6
return nil
}
-func (c *Controller) listUpstreamCache(ctx context.Context, upstreamMapA6 map[string]string) error {
- upstreamsInA6, err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).Upstream().List(ctx)
+func (p *apisixProvider) listUpstreamCache(ctx context.Context, upstreamMapA6 map[string]string) error {
+ upstreamsInA6, err := p.common.APISIX.Cluster(p.common.Config.APISIX.DefaultClusterName).Upstream().List(ctx)
if err != nil {
return err
} else {
@@ -303,8 +303,8 @@ func (c *Controller) listUpstreamCache(ctx context.Context, upstreamMapA6 map[st
return nil
}
-func (c *Controller) listSSLCache(ctx context.Context, sslMapA6 map[string]string) error {
- sslInA6, err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).SSL().List(ctx)
+func (p *apisixProvider) listSSLCache(ctx context.Context, sslMapA6 map[string]string) error {
+ sslInA6, err := p.common.APISIX.Cluster(p.common.Config.APISIX.DefaultClusterName).SSL().List(ctx)
if err != nil {
return err
} else {
@@ -315,8 +315,8 @@ func (c *Controller) listSSLCache(ctx context.Context, sslMapA6 map[string]strin
return nil
}
-func (c *Controller) listConsumerCache(ctx context.Context, consumerMapA6 map[string]string) error {
- consumerInA6, err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).Consumer().List(ctx)
+func (p *apisixProvider) listConsumerCache(ctx context.Context, consumerMapA6 map[string]string) error {
+ consumerInA6, err := p.common.APISIX.Cluster(p.common.Config.APISIX.DefaultClusterName).Consumer().List(ctx)
if err != nil {
return err
} else {
@@ -327,8 +327,8 @@ func (c *Controller) listConsumerCache(ctx context.Context, consumerMapA6 map[st
return nil
}
-func (c *Controller) listPluginConfigCache(ctx context.Context, pluginConfigMapA6 map[string]string) error {
- pluginConfigInA6, err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).PluginConfig().List(ctx)
+func (p *apisixProvider) listPluginConfigCache(ctx context.Context, pluginConfigMapA6 map[string]string) error {
+ pluginConfigInA6, err := p.common.APISIX.Cluster(p.common.Config.APISIX.DefaultClusterName).PluginConfig().List(ctx)
if err != nil {
return err
} else {
diff --git a/pkg/kube/translation/global_rule.go b/pkg/providers/apisix/translation/apisix_cluster_config.go
similarity index 100%
rename from pkg/kube/translation/global_rule.go
rename to pkg/providers/apisix/translation/apisix_cluster_config.go
diff --git a/pkg/kube/translation/global_rule_test.go b/pkg/providers/apisix/translation/apisix_cluster_config_test.go
similarity index 100%
rename from pkg/kube/translation/global_rule_test.go
rename to pkg/providers/apisix/translation/apisix_cluster_config_test.go
diff --git a/pkg/kube/translation/apisix_consumer.go b/pkg/providers/apisix/translation/apisix_consumer.go
similarity index 100%
rename from pkg/kube/translation/apisix_consumer.go
rename to pkg/providers/apisix/translation/apisix_consumer.go
diff --git a/pkg/kube/translation/apisix_consumer_test.go b/pkg/providers/apisix/translation/apisix_consumer_test.go
similarity index 100%
rename from pkg/kube/translation/apisix_consumer_test.go
rename to pkg/providers/apisix/translation/apisix_consumer_test.go
diff --git a/pkg/kube/translation/plugin.go b/pkg/providers/apisix/translation/apisix_plugin.go
similarity index 97%
rename from pkg/kube/translation/plugin.go
rename to pkg/providers/apisix/translation/apisix_plugin.go
index f9236ae8..4c726ede 100644
--- a/pkg/kube/translation/plugin.go
+++ b/pkg/providers/apisix/translation/apisix_plugin.go
@@ -20,6 +20,7 @@ import (
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"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
@@ -38,24 +39,24 @@ var (
_hmacAuthMaxReqBodyDefaultValue = int64(524288)
)
-func (t *translator) translateTrafficSplitPlugin(ctx *TranslateContext, ns string, defaultBackendWeight int,
+func (t *translator) translateTrafficSplitPlugin(ctx *translation.TranslateContext, ns string, defaultBackendWeight int,
backends []configv2.ApisixRouteHTTPBackend) (*apisixv1.TrafficSplitConfig, error) {
var (
wups []apisixv1.TrafficSplitConfigRuleWeightedUpstream
)
for _, backend := range backends {
- svcClusterIP, svcPort, err := t.getServiceClusterIPAndPort(&backend, ns)
+ svcClusterIP, svcPort, err := t.GetServiceClusterIPAndPort(&backend, ns)
if err != nil {
return nil, err
}
- ups, err := t.translateUpstream(ns, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ns, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return nil, err
}
ctx.AddUpstream(ups)
- weight := _defaultWeight
+ weight := translation.DefaultWeight
if backend.Weight != nil {
weight = *backend.Weight
}
diff --git a/pkg/kube/translation/plugin_test.go b/pkg/providers/apisix/translation/apisix_plugin_test.go
similarity index 95%
rename from pkg/kube/translation/plugin_test.go
rename to pkg/providers/apisix/translation/apisix_plugin_test.go
index 46c32dce..2c0b224c 100644
--- a/pkg/kube/translation/plugin_test.go
+++ b/pkg/providers/apisix/translation/apisix_plugin_test.go
@@ -33,6 +33,7 @@ import (
configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
apisixfake "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/fake"
apisixinformers "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
)
func TestTranslateTrafficSplitPlugin(t *testing.T) {
@@ -176,13 +177,15 @@ func TestTranslateTrafficSplitPlugin(t *testing.T) {
}
tr := &translator{&TranslatorOptions{
+ ServiceLister: svcLister,
+ }, translation.NewTranslator(&translation.TranslatorOptions{
ServiceLister: svcLister,
EndpointLister: epLister,
ApisixUpstreamLister: auLister,
APIVersion: config.DefaultAPIVersion,
- }}
- ctx := &TranslateContext{
- upstreamMap: make(map[string]struct{}),
+ })}
+ ctx := &translation.TranslateContext{
+ UpstreamMap: make(map[string]struct{}),
}
cfg, err := tr.translateTrafficSplitPlugin(ctx, ar1.Namespace, 30, backends)
assert.Nil(t, err)
@@ -351,12 +354,16 @@ func TestTranslateTrafficSplitPluginWithSameUpstreams(t *testing.T) {
}
tr := &translator{&TranslatorOptions{
+ ServiceLister: svcLister,
+ }, translation.NewTranslator(&translation.TranslatorOptions{
ServiceLister: svcLister,
EndpointLister: epLister,
ApisixUpstreamLister: auLister,
APIVersion: config.DefaultAPIVersion,
- }}
- ctx := &TranslateContext{upstreamMap: make(map[string]struct{})}
+ })}
+ ctx := &translation.TranslateContext{
+ UpstreamMap: make(map[string]struct{}),
+ }
cfg, err := tr.translateTrafficSplitPlugin(ctx, ar1.Namespace, 30, backends)
assert.Nil(t, err)
@@ -519,12 +526,14 @@ func TestTranslateTrafficSplitPluginBadCases(t *testing.T) {
}
tr := &translator{&TranslatorOptions{
+ ServiceLister: svcLister,
+ }, translation.NewTranslator(&translation.TranslatorOptions{
ServiceLister: svcLister,
EndpointLister: epLister,
ApisixUpstreamLister: auLister,
APIVersion: config.DefaultAPIVersion,
- }}
- ctx := &TranslateContext{upstreamMap: make(map[string]struct{})}
+ })}
+ ctx := &translation.TranslateContext{UpstreamMap: make(map[string]struct{})}
cfg, err := tr.translateTrafficSplitPlugin(ctx, ar1.Namespace, 30, backends)
assert.Nil(t, cfg)
assert.Len(t, ctx.Upstreams, 0)
@@ -533,7 +542,7 @@ func TestTranslateTrafficSplitPluginBadCases(t *testing.T) {
backends[0].ServiceName = "svc-1"
backends[1].ServicePort.StrVal = "port-not-found"
- ctx = &TranslateContext{upstreamMap: make(map[string]struct{})}
+ ctx = &translation.TranslateContext{UpstreamMap: make(map[string]struct{})}
cfg, err = tr.translateTrafficSplitPlugin(ctx, ar1.Namespace, 30, backends)
assert.Nil(t, cfg)
assert.NotNil(t, err)
@@ -541,7 +550,7 @@ func TestTranslateTrafficSplitPluginBadCases(t *testing.T) {
backends[1].ServicePort.StrVal = "port2"
backends[1].ResolveGranularity = "service"
- ctx = &TranslateContext{upstreamMap: make(map[string]struct{})}
+ ctx = &translation.TranslateContext{UpstreamMap: make(map[string]struct{})}
cfg, err = tr.translateTrafficSplitPlugin(ctx, ar1.Namespace, 30, backends)
assert.Nil(t, cfg)
assert.NotNil(t, err)
@@ -582,11 +591,10 @@ func TestTranslateConsumerKeyAuthWithSecretRef(t *testing.T) {
})
go secretInformer.Run(stopCh)
- tr := &translator{
- &TranslatorOptions{
- SecretLister: secretLister,
- },
- }
+ tr := &translator{&TranslatorOptions{
+ SecretLister: secretLister,
+ }, translation.NewTranslator(nil)}
+
_, err := client.CoreV1().Secrets("default").Create(context.Background(), sec, metav1.CreateOptions{})
assert.Nil(t, err)
@@ -656,11 +664,10 @@ func TestTranslateConsumerBasicAuthWithSecretRef(t *testing.T) {
})
go secretInformer.Run(stopCh)
- tr := &translator{
- &TranslatorOptions{
- SecretLister: secretLister,
- },
- }
+ tr := &translator{&TranslatorOptions{
+ SecretLister: secretLister,
+ }, translation.NewTranslator(nil)}
+
_, err := client.CoreV1().Secrets("default").Create(context.Background(), sec, metav1.CreateOptions{})
assert.Nil(t, err)
@@ -769,11 +776,10 @@ func TestTranslateConsumerJwtAuthWithSecretRef(t *testing.T) {
})
go secretInformer.Run(stopCh)
- tr := &translator{
- &TranslatorOptions{
- SecretLister: secretLister,
- },
- }
+ tr := &translator{&TranslatorOptions{
+ SecretLister: secretLister,
+ }, translation.NewTranslator(nil)}
+
_, err := client.CoreV1().Secrets("default").Create(context.Background(), sec, metav1.CreateOptions{})
assert.Nil(t, err)
@@ -898,11 +904,10 @@ func TestTranslateConsumerWolfRBACWithSecretRef(t *testing.T) {
})
go secretInformer.Run(stopCh)
- tr := &translator{
- &TranslatorOptions{
- SecretLister: secretLister,
- },
- }
+ tr := &translator{&TranslatorOptions{
+ SecretLister: secretLister,
+ }, translation.NewTranslator(nil)}
+
_, err := client.CoreV1().Secrets("default").Create(context.Background(), sec, metav1.CreateOptions{})
assert.Nil(t, err)
@@ -995,11 +1000,10 @@ func TestTranslateConsumerHMACAuthPluginWithSecretRef(t *testing.T) {
})
go secretInformer.Run(stopCh)
- tr := &translator{
- &TranslatorOptions{
- SecretLister: secretLister,
- },
- }
+ tr := &translator{&TranslatorOptions{
+ SecretLister: secretLister,
+ }, translation.NewTranslator(nil)}
+
_, err := client.CoreV1().Secrets("default").Create(context.Background(), sec, metav1.CreateOptions{})
assert.Nil(t, err)
diff --git a/pkg/kube/translation/apisix_pluginconfig.go b/pkg/providers/apisix/translation/apisix_pluginconfig.go
similarity index 86%
rename from pkg/kube/translation/apisix_pluginconfig.go
rename to pkg/providers/apisix/translation/apisix_pluginconfig.go
index 4bf35510..bea90ed4 100644
--- a/pkg/kube/translation/apisix_pluginconfig.go
+++ b/pkg/providers/apisix/translation/apisix_pluginconfig.go
@@ -21,11 +21,12 @@ import (
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"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
-func (t *translator) TranslatePluginConfigV2beta3(config *configv2beta3.ApisixPluginConfig) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslatePluginConfigV2beta3(config *configv2beta3.ApisixPluginConfig) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
pluginMap := make(apisixv1.Plugins)
if len(config.Spec.Plugins) > 0 {
for _, plugin := range config.Spec.Plugins {
@@ -55,8 +56,8 @@ func (t *translator) TranslatePluginConfigV2beta3(config *configv2beta3.ApisixPl
return ctx, nil
}
-func (t *translator) TranslatePluginConfigV2beta3NotStrictly(config *configv2beta3.ApisixPluginConfig) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslatePluginConfigV2beta3NotStrictly(config *configv2beta3.ApisixPluginConfig) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
pc := apisixv1.NewDefaultPluginConfig()
pc.Name = apisixv1.ComposePluginConfigName(config.Namespace, config.Name)
pc.ID = id.GenID(pc.Name)
@@ -64,8 +65,8 @@ func (t *translator) TranslatePluginConfigV2beta3NotStrictly(config *configv2bet
return ctx, nil
}
-func (t *translator) TranslatePluginConfigV2(config *configv2.ApisixPluginConfig) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslatePluginConfigV2(config *configv2.ApisixPluginConfig) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
pluginMap := make(apisixv1.Plugins)
if len(config.Spec.Plugins) > 0 {
for _, plugin := range config.Spec.Plugins {
@@ -95,8 +96,8 @@ func (t *translator) TranslatePluginConfigV2(config *configv2.ApisixPluginConfig
return ctx, nil
}
-func (t *translator) TranslatePluginConfigV2NotStrictly(config *configv2.ApisixPluginConfig) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslatePluginConfigV2NotStrictly(config *configv2.ApisixPluginConfig) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
pc := apisixv1.NewDefaultPluginConfig()
pc.Name = apisixv1.ComposePluginConfigName(config.Namespace, config.Name)
pc.ID = id.GenID(pc.Name)
diff --git a/pkg/kube/translation/apisix_pluginconfig_test.go b/pkg/providers/apisix/translation/apisix_pluginconfig_test.go
similarity index 100%
rename from pkg/kube/translation/apisix_pluginconfig_test.go
rename to pkg/providers/apisix/translation/apisix_pluginconfig_test.go
diff --git a/pkg/kube/translation/apisix_route.go b/pkg/providers/apisix/translation/apisix_route.go
similarity index 74%
rename from pkg/kube/translation/apisix_route.go
rename to pkg/providers/apisix/translation/apisix_route.go
index e2bcf1e7..bf32f733 100644
--- a/pkg/kube/translation/apisix_route.go
+++ b/pkg/providers/apisix/translation/apisix_route.go
@@ -17,21 +17,26 @@ package translation
import (
"context"
"errors"
+ "fmt"
"strings"
"go.uber.org/zap"
+ "k8s.io/apimachinery/pkg/util/intstr"
+ "github.com/apache/apisix-ingress-controller/pkg/config"
"github.com/apache/apisix-ingress-controller/pkg/id"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
configv2beta2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta2"
configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
_const "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/const"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
-func (t *translator) TranslateRouteV2beta2(ar *configv2beta2.ApisixRoute) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateRouteV2beta2(ar *configv2beta2.ApisixRoute) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
if err := t.translateHTTPRouteV2beta2(ctx, ar); err != nil {
return nil, err
@@ -42,8 +47,8 @@ func (t *translator) TranslateRouteV2beta2(ar *configv2beta2.ApisixRoute) (*Tran
return ctx, nil
}
-func (t *translator) TranslateRouteV2beta2NotStrictly(ar *configv2beta2.ApisixRoute) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateRouteV2beta2NotStrictly(ar *configv2beta2.ApisixRoute) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
if err := t.translateHTTPRouteV2beta2NotStrictly(ctx, ar); err != nil {
return nil, err
@@ -54,8 +59,8 @@ func (t *translator) TranslateRouteV2beta2NotStrictly(ar *configv2beta2.ApisixRo
return ctx, nil
}
-func (t *translator) TranslateRouteV2beta3(ar *configv2beta3.ApisixRoute) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateRouteV2beta3(ar *configv2beta3.ApisixRoute) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
if err := t.translateHTTPRouteV2beta3(ctx, ar); err != nil {
return nil, err
@@ -66,8 +71,8 @@ func (t *translator) TranslateRouteV2beta3(ar *configv2beta3.ApisixRoute) (*Tran
return ctx, nil
}
-func (t *translator) TranslateRouteV2beta3NotStrictly(ar *configv2beta3.ApisixRoute) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateRouteV2beta3NotStrictly(ar *configv2beta3.ApisixRoute) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
if err := t.translateHTTPRouteV2beta3NotStrictly(ctx, ar); err != nil {
return nil, err
@@ -78,8 +83,8 @@ func (t *translator) TranslateRouteV2beta3NotStrictly(ar *configv2beta3.ApisixRo
return ctx, nil
}
-func (t *translator) TranslateRouteV2(ar *configv2.ApisixRoute) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateRouteV2(ar *configv2.ApisixRoute) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
if err := t.translateHTTPRouteV2(ctx, ar); err != nil {
return nil, err
@@ -90,8 +95,8 @@ func (t *translator) TranslateRouteV2(ar *configv2.ApisixRoute) (*TranslateConte
return ctx, nil
}
-func (t *translator) TranslateRouteV2NotStrictly(ar *configv2.ApisixRoute) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateRouteV2NotStrictly(ar *configv2.ApisixRoute) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
if err := t.translateHTTPRouteV2NotStrictly(ctx, ar); err != nil {
return nil, err
@@ -102,7 +107,7 @@ func (t *translator) TranslateRouteV2NotStrictly(ar *configv2.ApisixRoute) (*Tra
return ctx, nil
}
-func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *configv2beta2.ApisixRoute) error {
+func (t *translator) translateHTTPRouteV2beta2(ctx *translation.TranslateContext, ar *configv2beta2.ApisixRoute) error {
ruleNameMap := make(map[string]struct{})
for _, part := range ar.Spec.HTTP {
if _, ok := ruleNameMap[part.Name]; ok {
@@ -115,7 +120,7 @@ func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *config
backend := backends[0]
backends = backends[1:]
- svcClusterIP, svcPort, err := t.getServiceClusterIPAndPort(&backend, ar.Namespace)
+ svcClusterIP, svcPort, err := t.GetServiceClusterIPAndPort(&backend, ar.Namespace)
if err != nil {
log.Errorw("failed to get service port in backend",
zap.Any("backend", backend),
@@ -152,7 +157,7 @@ func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *config
var exprs [][]apisixv1.StringOrSlice
if part.Match.NginxVars != nil {
- exprs, err = t.translateRouteMatchExprs(part.Match.NginxVars)
+ exprs, err = t.TranslateRouteMatchExprs(part.Match.NginxVars)
if err != nil {
log.Errorw("ApisixRoute with bad nginxVars",
zap.Error(err),
@@ -161,7 +166,7 @@ func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *config
return err
}
}
- if err := validateRemoteAddrs(part.Match.RemoteAddrs); err != nil {
+ if err := translation.ValidateRemoteAddrs(part.Match.RemoteAddrs); err != nil {
log.Errorw("ApisixRoute with invalid remote addrs",
zap.Error(err),
zap.Strings("remote_addrs", part.Match.RemoteAddrs),
@@ -185,7 +190,7 @@ func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *config
route.Plugins = pluginMap
if len(backends) > 0 {
- weight := _defaultWeight
+ weight := translation.DefaultWeight
if backend.Weight != nil {
weight = *backend.Weight
}
@@ -203,7 +208,7 @@ func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *config
}
ctx.AddRoute(route)
if !ctx.CheckUpstreamExist(upstreamName) {
- ups, err := t.translateUpstream(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return err
}
@@ -213,7 +218,7 @@ func (t *translator) translateHTTPRouteV2beta2(ctx *TranslateContext, ar *config
return nil
}
-func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *configv2beta3.ApisixRoute) error {
+func (t *translator) translateHTTPRouteV2beta3(ctx *translation.TranslateContext, ar *configv2beta3.ApisixRoute) error {
ruleNameMap := make(map[string]struct{})
for _, part := range ar.Spec.HTTP {
if _, ok := ruleNameMap[part.Name]; ok {
@@ -226,7 +231,7 @@ func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *config
backend := backends[0]
backends = backends[1:]
- svcClusterIP, svcPort, err := t.getServiceClusterIPAndPort(&backend, ar.Namespace)
+ svcClusterIP, svcPort, err := t.GetServiceClusterIPAndPort(&backend, ar.Namespace)
if err != nil {
log.Errorw("failed to get service port in backend",
zap.Any("backend", backend),
@@ -286,7 +291,7 @@ func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *config
var exprs [][]apisixv1.StringOrSlice
if part.Match.NginxVars != nil {
- exprs, err = t.translateRouteMatchExprs(part.Match.NginxVars)
+ exprs, err = t.TranslateRouteMatchExprs(part.Match.NginxVars)
if err != nil {
log.Errorw("ApisixRoute with bad nginxVars",
zap.Error(err),
@@ -295,7 +300,7 @@ func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *config
return err
}
}
- if err := validateRemoteAddrs(part.Match.RemoteAddrs); err != nil {
+ if err := translation.ValidateRemoteAddrs(part.Match.RemoteAddrs); err != nil {
log.Errorw("ApisixRoute with invalid remote addrs",
zap.Error(err),
zap.Strings("remote_addrs", part.Match.RemoteAddrs),
@@ -323,7 +328,7 @@ func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *config
}
if len(backends) > 0 {
- weight := _defaultWeight
+ weight := translation.DefaultWeight
if backend.Weight != nil {
weight = *backend.Weight
}
@@ -339,7 +344,7 @@ func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *config
}
ctx.AddRoute(route)
if !ctx.CheckUpstreamExist(upstreamName) {
- ups, err := t.translateUpstream(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return err
}
@@ -349,7 +354,7 @@ func (t *translator) translateHTTPRouteV2beta3(ctx *TranslateContext, ar *config
return nil
}
-func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.ApisixRoute) error {
+func (t *translator) translateHTTPRouteV2(ctx *translation.TranslateContext, ar *configv2.ApisixRoute) error {
ruleNameMap := make(map[string]struct{})
for _, part := range ar.Spec.HTTP {
if _, ok := ruleNameMap[part.Name]; ok {
@@ -362,7 +367,7 @@ func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.Ap
backend := backends[0]
backends = backends[1:]
- svcClusterIP, svcPort, err := t.getServiceClusterIPAndPort(&backend, ar.Namespace)
+ svcClusterIP, svcPort, err := t.GetServiceClusterIPAndPort(&backend, ar.Namespace)
if err != nil {
log.Errorw("failed to get service port in backend",
zap.Any("backend", backend),
@@ -422,7 +427,7 @@ func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.Ap
var exprs [][]apisixv1.StringOrSlice
if part.Match.NginxVars != nil {
- exprs, err = t.translateRouteMatchExprs(part.Match.NginxVars)
+ exprs, err = t.TranslateRouteMatchExprs(part.Match.NginxVars)
if err != nil {
log.Errorw("ApisixRoute with bad nginxVars",
zap.Error(err),
@@ -431,7 +436,7 @@ func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.Ap
return err
}
}
- if err := validateRemoteAddrs(part.Match.RemoteAddrs); err != nil {
+ if err := translation.ValidateRemoteAddrs(part.Match.RemoteAddrs); err != nil {
log.Errorw("ApisixRoute with invalid remote addrs",
zap.Error(err),
zap.Strings("remote_addrs", part.Match.RemoteAddrs),
@@ -459,7 +464,7 @@ func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.Ap
}
if len(backends) > 0 {
- weight := _defaultWeight
+ weight := translation.DefaultWeight
if backend.Weight != nil {
weight = *backend.Weight
}
@@ -475,7 +480,7 @@ func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.Ap
}
ctx.AddRoute(route)
if !ctx.CheckUpstreamExist(upstreamName) {
- ups, err := t.translateUpstream(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return err
}
@@ -485,7 +490,7 @@ func (t *translator) translateHTTPRouteV2(ctx *TranslateContext, ar *configv2.Ap
return nil
}
-func (t *translator) translateRouteMatchExprs(nginxVars []configv2.ApisixRouteHTTPMatchExpr) ([][]apisixv1.StringOrSlice, error) {
+func (t *translator) TranslateRouteMatchExprs(nginxVars []configv2.ApisixRouteHTTPMatchExpr) ([][]apisixv1.StringOrSlice, error) {
var (
vars [][]apisixv1.StringOrSlice
op string
@@ -586,7 +591,7 @@ func (t *translator) translateRouteMatchExprs(nginxVars []configv2.ApisixRouteHT
}
// translateHTTPRouteV2beta2NotStrictly translates http route with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateHTTPRouteV2beta2NotStrictly(ctx *TranslateContext, ar *configv2beta2.ApisixRoute) error {
+func (t *translator) translateHTTPRouteV2beta2NotStrictly(ctx *translation.TranslateContext, ar *configv2beta2.ApisixRoute) error {
for _, part := range ar.Spec.HTTP {
backends := part.Backends
// Use the first backend as the default backend in Route,
@@ -609,7 +614,7 @@ func (t *translator) translateHTTPRouteV2beta2NotStrictly(ctx *TranslateContext,
}
// translateHTTPRouteV2beta3NotStrictly translates http route with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateHTTPRouteV2beta3NotStrictly(ctx *TranslateContext, ar *configv2beta3.ApisixRoute) error {
+func (t *translator) translateHTTPRouteV2beta3NotStrictly(ctx *translation.TranslateContext, ar *configv2beta3.ApisixRoute) error {
for _, part := range ar.Spec.HTTP {
backends := part.Backends
// Use the first backend as the default backend in Route,
@@ -668,7 +673,7 @@ func (t *translator) translateHTTPRouteV2beta3NotStrictly(ctx *TranslateContext,
}
// translateHTTPRouteV2NotStrictly translates http route with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateHTTPRouteV2NotStrictly(ctx *TranslateContext, ar *configv2.ApisixRoute) error {
+func (t *translator) translateHTTPRouteV2NotStrictly(ctx *translation.TranslateContext, ar *configv2.ApisixRoute) error {
for _, part := range ar.Spec.HTTP {
backends := part.Backends
// Use the first backend as the default backend in Route,
@@ -726,7 +731,7 @@ func (t *translator) translateHTTPRouteV2NotStrictly(ctx *TranslateContext, ar *
return nil
}
-func (t *translator) translateStreamRouteV2beta2(ctx *TranslateContext, ar *configv2beta2.ApisixRoute) error {
+func (t *translator) translateStreamRouteV2beta2(ctx *translation.TranslateContext, ar *configv2beta2.ApisixRoute) error {
ruleNameMap := make(map[string]struct{})
for _, part := range ar.Spec.Stream {
if _, ok := ruleNameMap[part.Name]; ok {
@@ -747,7 +752,7 @@ func (t *translator) translateStreamRouteV2beta2(ctx *TranslateContext, ar *conf
name := apisixv1.ComposeStreamRouteName(ar.Namespace, ar.Name, part.Name)
sr.ID = id.GenID(name)
sr.ServerPort = part.Match.IngressPort
- ups, err := t.translateUpstream(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return err
}
@@ -761,7 +766,7 @@ func (t *translator) translateStreamRouteV2beta2(ctx *TranslateContext, ar *conf
return nil
}
-func (t *translator) translateStreamRouteV2beta3(ctx *TranslateContext, ar *configv2beta3.ApisixRoute) error {
+func (t *translator) translateStreamRouteV2beta3(ctx *translation.TranslateContext, ar *configv2beta3.ApisixRoute) error {
ruleNameMap := make(map[string]struct{})
for _, part := range ar.Spec.Stream {
if _, ok := ruleNameMap[part.Name]; ok {
@@ -782,7 +787,7 @@ func (t *translator) translateStreamRouteV2beta3(ctx *TranslateContext, ar *conf
name := apisixv1.ComposeStreamRouteName(ar.Namespace, ar.Name, part.Name)
sr.ID = id.GenID(name)
sr.ServerPort = part.Match.IngressPort
- ups, err := t.translateUpstream(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return err
}
@@ -796,7 +801,7 @@ func (t *translator) translateStreamRouteV2beta3(ctx *TranslateContext, ar *conf
return nil
}
-func (t *translator) translateStreamRouteV2(ctx *TranslateContext, ar *configv2.ApisixRoute) error {
+func (t *translator) translateStreamRouteV2(ctx *translation.TranslateContext, ar *configv2.ApisixRoute) error {
ruleNameMap := make(map[string]struct{})
for _, part := range ar.Spec.Stream {
if _, ok := ruleNameMap[part.Name]; ok {
@@ -817,7 +822,7 @@ func (t *translator) translateStreamRouteV2(ctx *TranslateContext, ar *configv2.
name := apisixv1.ComposeStreamRouteName(ar.Namespace, ar.Name, part.Name)
sr.ID = id.GenID(name)
sr.ServerPort = part.Match.IngressPort
- ups, err := t.translateUpstream(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
+ ups, err := t.translateService(ar.Namespace, backend.ServiceName, backend.Subset, backend.ResolveGranularity, svcClusterIP, svcPort)
if err != nil {
return err
}
@@ -832,7 +837,7 @@ func (t *translator) translateStreamRouteV2(ctx *TranslateContext, ar *configv2.
}
// translateStreamRouteNotStrictlyV2beta2 translates tcp route with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateStreamRouteNotStrictlyV2beta2(ctx *TranslateContext, ar *configv2beta2.ApisixRoute) error {
+func (t *translator) translateStreamRouteNotStrictlyV2beta2(ctx *translation.TranslateContext, ar *configv2beta2.ApisixRoute) error {
for _, part := range ar.Spec.Stream {
backend := &part.Backend
sr := apisixv1.NewDefaultStreamRoute()
@@ -853,7 +858,7 @@ func (t *translator) translateStreamRouteNotStrictlyV2beta2(ctx *TranslateContex
}
// translateStreamRouteNotStrictlyV2beta3 translates tcp route with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateStreamRouteNotStrictlyV2beta3(ctx *TranslateContext, ar *configv2beta3.ApisixRoute) error {
+func (t *translator) translateStreamRouteNotStrictlyV2beta3(ctx *translation.TranslateContext, ar *configv2beta3.ApisixRoute) error {
for _, part := range ar.Spec.Stream {
backend := &part.Backend
sr := apisixv1.NewDefaultStreamRoute()
@@ -874,7 +879,7 @@ func (t *translator) translateStreamRouteNotStrictlyV2beta3(ctx *TranslateContex
}
// translateStreamRouteNotStrictlyV2 translates tcp route with a loose way, only generate ID and Name for delete Event.
-func (t *translator) translateStreamRouteNotStrictlyV2(ctx *TranslateContext, ar *configv2.ApisixRoute) error {
+func (t *translator) translateStreamRouteNotStrictlyV2(ctx *translation.TranslateContext, ar *configv2.ApisixRoute) error {
for _, part := range ar.Spec.Stream {
backend := &part.Backend
sr := apisixv1.NewDefaultStreamRoute()
@@ -894,8 +899,180 @@ func (t *translator) translateStreamRouteNotStrictlyV2(ctx *TranslateContext, ar
return nil
}
-func (t *translator) translateOldRouteV2(ar *configv2.ApisixRoute) (*TranslateContext, error) {
- oldCtx := DefaultEmptyTranslateContext()
+func (t *translator) GetServiceClusterIPAndPort(backend *configv2.ApisixRouteHTTPBackend, ns string) (string, int32, error) {
+ svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
+ if err != nil {
+ return "", 0, err
+ }
+ svcPort := int32(-1)
+ if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
+ log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
+ zap.Any("namespace", ns),
+ zap.Any("service", svc),
+ )
+ return "", 0, errors.New("conflict headless service and backend resolve granularity")
+ }
+loop:
+ for _, port := range svc.Spec.Ports {
+ switch backend.ServicePort.Type {
+ case intstr.Int:
+ if backend.ServicePort.IntVal == port.Port {
+ svcPort = port.Port
+ break loop
+ }
+ case intstr.String:
+ if backend.ServicePort.StrVal == port.Name {
+ svcPort = port.Port
+ break loop
+ }
+ }
+ }
+ if svcPort == -1 {
+ log.Errorw("ApisixRoute refers to non-existent Service port",
+ zap.String("namespace", ns),
+ zap.String("port", backend.ServicePort.String()),
+ )
+ return "", 0, err
+ }
+
+ return svc.Spec.ClusterIP, svcPort, nil
+}
+
+// getStreamServiceClusterIPAndPortV2beta2 is for v2beta2 streamRoute
+func (t *translator) getStreamServiceClusterIPAndPortV2beta2(backend configv2beta2.ApisixRouteStreamBackend, ns string) (string, int32, error) {
+ svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
+ if err != nil {
+ return "", 0, err
+ }
+ svcPort := int32(-1)
+ if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
+ log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
+ zap.String("ApisixRoute namespace", ns),
+ zap.Any("service", svc),
+ )
+ return "", 0, errors.New("conflict headless service and backend resolve granularity")
+ }
+loop:
+ for _, port := range svc.Spec.Ports {
+ switch backend.ServicePort.Type {
+ case intstr.Int:
+ if backend.ServicePort.IntVal == port.Port {
+ svcPort = port.Port
+ break loop
+ }
+ case intstr.String:
+ if backend.ServicePort.StrVal == port.Name {
+ svcPort = port.Port
+ break loop
+ }
+ }
+ }
+ if svcPort == -1 {
+ log.Errorw("ApisixRoute refers to non-existent Service port",
+ zap.String("ApisixRoute namespace", ns),
+ zap.String("port", backend.ServicePort.String()),
+ )
+ return "", 0, err
+ }
+
+ return svc.Spec.ClusterIP, svcPort, nil
+}
+
+// getStreamServiceClusterIPAndPortV2beta3 is for v2beta3 streamRoute
+func (t *translator) getStreamServiceClusterIPAndPortV2beta3(backend configv2beta3.ApisixRouteStreamBackend, ns string) (string, int32, error) {
+ svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
+ if err != nil {
+ return "", 0, err
+ }
+ svcPort := int32(-1)
+ if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
+ log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
+ zap.String("ApisixRoute namespace", ns),
+ zap.Any("service", svc),
+ )
+ return "", 0, errors.New("conflict headless service and backend resolve granularity")
+ }
+loop:
+ for _, port := range svc.Spec.Ports {
+ switch backend.ServicePort.Type {
+ case intstr.Int:
+ if backend.ServicePort.IntVal == port.Port {
+ svcPort = port.Port
+ break loop
+ }
+ case intstr.String:
+ if backend.ServicePort.StrVal == port.Name {
+ svcPort = port.Port
+ break loop
+ }
+ }
+ }
+ if svcPort == -1 {
+ log.Errorw("ApisixRoute refers to non-existent Service port",
+ zap.String("ApisixRoute namespace", ns),
+ zap.String("port", backend.ServicePort.String()),
+ )
+ return "", 0, err
+ }
+
+ return svc.Spec.ClusterIP, svcPort, nil
+}
+
+// getStreamServiceClusterIPAndPortV2 is for v2 streamRoute
+func (t *translator) getStreamServiceClusterIPAndPortV2(backend configv2.ApisixRouteStreamBackend, ns string) (string, int32, error) {
+ svc, err := t.ServiceLister.Services(ns).Get(backend.ServiceName)
+ if err != nil {
+ return "", 0, err
+ }
+ svcPort := int32(-1)
+ if backend.ResolveGranularity == "service" && svc.Spec.ClusterIP == "" {
+ log.Errorw("ApisixRoute refers to a headless service but want to use the service level resolve granularity",
+ zap.String("ApisixRoute namespace", ns),
+ zap.Any("service", svc),
+ )
+ return "", 0, errors.New("conflict headless service and backend resolve granularity")
+ }
+loop:
+ for _, port := range svc.Spec.Ports {
+ switch backend.ServicePort.Type {
+ case intstr.Int:
+ if backend.ServicePort.IntVal == port.Port {
+ svcPort = port.Port
+ break loop
+ }
+ case intstr.String:
+ if backend.ServicePort.StrVal == port.Name {
+ svcPort = port.Port
+ break loop
+ }
+ }
+ }
+ if svcPort == -1 {
+ log.Errorw("ApisixRoute refers to non-existent Service port",
+ zap.String("ApisixRoute namespace", ns),
+ zap.String("port", backend.ServicePort.String()),
+ )
+ return "", 0, err
+ }
+
+ return svc.Spec.ClusterIP, svcPort, nil
+}
+
+func (t *translator) TranslateOldRoute(ar kube.ApisixRoute) (*translation.TranslateContext, error) {
+ switch ar.GroupVersion() {
+ case config.ApisixV2:
+ return t.translateOldRouteV2(ar.V2())
+ case config.ApisixV2beta3:
+ return t.translateOldRouteV2beta3(ar.V2beta3())
+ case config.ApisixV2beta2:
+ return translation.DefaultEmptyTranslateContext(), nil
+ default:
+ return nil, fmt.Errorf("translator: source group version not supported: %s", ar.GroupVersion())
+ }
+}
+
+func (t *translator) translateOldRouteV2(ar *configv2.ApisixRoute) (*translation.TranslateContext, error) {
+ oldCtx := translation.DefaultEmptyTranslateContext()
for _, part := range ar.Spec.Stream {
name := apisixv1.ComposeStreamRouteName(ar.Namespace, ar.Name, part.Name)
@@ -931,8 +1108,8 @@ func (t *translator) translateOldRouteV2(ar *configv2.ApisixRoute) (*TranslateCo
return oldCtx, nil
}
-func (t *translator) translateOldRouteV2beta3(ar *configv2beta3.ApisixRoute) (*TranslateContext, error) {
- oldCtx := DefaultEmptyTranslateContext()
+func (t *translator) translateOldRouteV2beta3(ar *configv2beta3.ApisixRoute) (*translation.TranslateContext, error) {
+ oldCtx := translation.DefaultEmptyTranslateContext()
for _, part := range ar.Spec.Stream {
name := apisixv1.ComposeStreamRouteName(ar.Namespace, ar.Name, part.Name)
diff --git a/pkg/kube/translation/apisix_route_test.go b/pkg/providers/apisix/translation/apisix_route_test.go
similarity index 98%
rename from pkg/kube/translation/apisix_route_test.go
rename to pkg/providers/apisix/translation/apisix_route_test.go
index cc6af876..57f8e8ed 100644
--- a/pkg/kube/translation/apisix_route_test.go
+++ b/pkg/providers/apisix/translation/apisix_route_test.go
@@ -35,6 +35,7 @@ import (
fakeapisix "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/fake"
apisixinformers "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions"
_const "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/const"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
@@ -131,7 +132,7 @@ func TestRouteMatchExpr(t *testing.T) {
},
},
}
- results, err := tr.translateRouteMatchExprs(exprs)
+ results, err := tr.TranslateRouteMatchExprs(exprs)
assert.Nil(t, err)
assert.Len(t, results, 10)
@@ -257,14 +258,17 @@ func mockTranslatorV2beta3(t *testing.T) (*translator, <-chan struct{}) {
tr := &translator{
&TranslatorOptions{
- EndpointLister: epLister,
+ ServiceLister: svcLister,
+ },
+ translation.NewTranslator(&translation.TranslatorOptions{
ServiceLister: svcLister,
+ EndpointLister: epLister,
ApisixUpstreamLister: kube.NewApisixUpstreamLister(
apisixInformersFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
apisixInformersFactory.Apisix().V2().ApisixUpstreams().Lister(),
),
APIVersion: config.ApisixV2beta3,
- },
+ }),
}
processCh := make(chan struct{}, 2)
@@ -418,6 +422,7 @@ func TestTranslateApisixRouteV2beta3WithEmptyPluginConfigName(t *testing.T) {
func TestTranslateApisixRouteV2beta3NotStrictly(t *testing.T) {
tr := &translator{
&TranslatorOptions{},
+ translation.NewTranslator(nil),
}
ar := &configv2beta3.ApisixRoute{
ObjectMeta: metav1.ObjectMeta{
diff --git a/pkg/kube/translation/apisix_ssl.go b/pkg/providers/apisix/translation/apisix_ssl.go
similarity index 65%
rename from pkg/kube/translation/apisix_ssl.go
rename to pkg/providers/apisix/translation/apisix_ssl.go
index 60450fa0..6eea68b3 100644
--- a/pkg/kube/translation/apisix_ssl.go
+++ b/pkg/providers/apisix/translation/apisix_ssl.go
@@ -15,31 +15,19 @@
package translation
import (
- "errors"
-
- v1 "k8s.io/api/core/v1"
-
"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"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
-var (
- // ErrUnknownSecretFormat means the secret doesn't contain required fields
- ErrUnknownSecretFormat = errors.New("unknown secret format")
- // ErrEmptyCert means the cert field in Kubernetes Secret is not found.
- ErrEmptyCert = errors.New("missing cert field")
- // ErrEmptyPrivKey means the key field in Kubernetes Secret is not found.
- ErrEmptyPrivKey = errors.New("missing key field")
-)
-
func (t *translator) TranslateSSLV2Beta3(tls *configv2beta3.ApisixTls) (*apisixv1.Ssl, error) {
s, err := t.SecretLister.Secrets(tls.Spec.Secret.Namespace).Get(tls.Spec.Secret.Name)
if err != nil {
return nil, err
}
- cert, key, err := t.ExtractKeyPair(s, true)
+ cert, key, err := translation.ExtractKeyPair(s, true)
if err != nil {
return nil, err
}
@@ -63,7 +51,7 @@ func (t *translator) TranslateSSLV2Beta3(tls *configv2beta3.ApisixTls) (*apisixv
if err != nil {
return nil, err
}
- ca, _, err := t.ExtractKeyPair(caSecret, false)
+ ca, _, err := translation.ExtractKeyPair(caSecret, false)
if err != nil {
return nil, err
}
@@ -81,7 +69,7 @@ func (t *translator) TranslateSSLV2(tls *configv2.ApisixTls) (*apisixv1.Ssl, err
if err != nil {
return nil, err
}
- cert, key, err := t.ExtractKeyPair(s, true)
+ cert, key, err := translation.ExtractKeyPair(s, true)
if err != nil {
return nil, err
}
@@ -105,7 +93,7 @@ func (t *translator) TranslateSSLV2(tls *configv2.ApisixTls) (*apisixv1.Ssl, err
if err != nil {
return nil, err
}
- ca, _, err := t.ExtractKeyPair(caSecret, false)
+ ca, _, err := translation.ExtractKeyPair(caSecret, false)
if err != nil {
return nil, err
}
@@ -117,45 +105,3 @@ func (t *translator) TranslateSSLV2(tls *configv2.ApisixTls) (*apisixv1.Ssl, err
return ssl, nil
}
-
-func (t *translator) ExtractKeyPair(s *v1.Secret, hasPrivateKey bool) ([]byte, []byte, error) {
- if _, ok := s.Data["cert"]; ok {
- return t.extractApisixSecretKeyPair(s, hasPrivateKey)
- } else if _, ok := s.Data[v1.TLSCertKey]; ok {
- return t.extractKubeSecretKeyPair(s, hasPrivateKey)
- } else {
- return nil, nil, ErrUnknownSecretFormat
- }
-}
-
-func (t *translator) extractApisixSecretKeyPair(s *v1.Secret, hasPrivateKey bool) (cert []byte, key []byte, err error) {
- var ok bool
- cert, ok = s.Data["cert"]
- if !ok {
- return nil, nil, ErrEmptyCert
- }
-
- if hasPrivateKey {
- key, ok = s.Data["key"]
- if !ok {
- return nil, nil, ErrEmptyPrivKey
- }
- }
- return
-}
-
-func (t *translator) extractKubeSecretKeyPair(s *v1.Secret, hasPrivateKey bool) (cert []byte, key []byte, err error) {
- var ok bool
- cert, ok = s.Data[v1.TLSCertKey]
- if !ok {
- return nil, nil, ErrEmptyCert
- }
-
- if hasPrivateKey {
- key, ok = s.Data[v1.TLSPrivateKeyKey]
- if !ok {
- return nil, nil, ErrEmptyPrivKey
- }
- }
- return
-}
diff --git a/pkg/providers/apisix/translation/apisix_upstream.go b/pkg/providers/apisix/translation/apisix_upstream.go
new file mode 100644
index 00000000..ac1e901b
--- /dev/null
+++ b/pkg/providers/apisix/translation/apisix_upstream.go
@@ -0,0 +1,48 @@
+// 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 translation
+
+import (
+ "github.com/apache/apisix-ingress-controller/pkg/id"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+// translateUpstreamNotStrictly translates Upstream nodes with a loose way, only generate ID and Name for delete Event.
+func (t *translator) translateUpstreamNotStrictly(namespace, svcName, subset string, svcPort int32) (*apisixv1.Upstream, error) {
+ ups := &apisixv1.Upstream{}
+ ups.Name = apisixv1.ComposeUpstreamName(namespace, svcName, subset, svcPort)
+ ups.ID = id.GenID(ups.Name)
+ return ups, nil
+}
+
+func (t *translator) translateService(namespace, svcName, subset, svcResolveGranularity, svcClusterIP string, svcPort int32) (*apisixv1.Upstream, error) {
+ ups, err := t.TranslateService(namespace, svcName, subset, svcPort)
+ if err != nil {
+ return nil, err
+ }
+ if svcResolveGranularity == "service" {
+ ups.Nodes = apisixv1.UpstreamNodes{
+ {
+ Host: svcClusterIP,
+ Port: int(svcPort),
+ Weight: translation.DefaultWeight,
+ },
+ }
+ }
+ ups.Name = apisixv1.ComposeUpstreamName(namespace, svcName, subset, svcPort)
+ ups.ID = id.GenID(ups.Name)
+ return ups, nil
+}
diff --git a/pkg/providers/apisix/translation/translator.go b/pkg/providers/apisix/translation/translator.go
new file mode 100644
index 00000000..ec4817c2
--- /dev/null
+++ b/pkg/providers/apisix/translation/translator.go
@@ -0,0 +1,106 @@
+// 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 translation
+
+import (
+ listerscorev1 "k8s.io/client-go/listers/core/v1"
+
+ "github.com/apache/apisix-ingress-controller/pkg/apisix"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ configv2beta2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta2"
+ configv2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+type TranslatorOptions struct {
+ Apisix apisix.APISIX
+ ClusterName string
+
+ ServiceLister listerscorev1.ServiceLister
+ SecretLister listerscorev1.SecretLister
+}
+
+type translator struct {
+ *TranslatorOptions
+ translation.Translator
+}
+
+type ApisixTranslator interface {
+ translation.Translator
+
+ // TranslateRouteV2beta2 translates the configv2beta2.ApisixRoute object into several Route,
+ // and Upstream resources.
+ TranslateRouteV2beta2(*configv2beta2.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateRouteV2beta2NotStrictly translates the configv2beta2.ApisixRoute object into several Route,
+ // and Upstream resources not strictly, only used for delete event.
+ TranslateRouteV2beta2NotStrictly(*configv2beta2.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateRouteV2beta3 translates the configv2beta3.ApisixRoute object into several Route,
+ // Upstream and PluginConfig resources.
+ TranslateRouteV2beta3(*configv2beta3.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateRouteV2beta3NotStrictly translates the configv2beta3.ApisixRoute object into several Route,
+ // Upstream and PluginConfig resources not strictly, only used for delete event.
+ TranslateRouteV2beta3NotStrictly(*configv2beta3.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateRouteV2 translates the configv2.ApisixRoute object into several Route,
+ // Upstream and PluginConfig resources.
+ TranslateRouteV2(*configv2.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateRouteV2NotStrictly translates the configv2.ApisixRoute object into several Route,
+ // Upstream and PluginConfig resources not strictly, only used for delete event.
+ TranslateRouteV2NotStrictly(*configv2.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateOldRoute get route and stream_route objects from cache
+ // Build upstream and plugin_config through route and stream_route
+ TranslateOldRoute(kube.ApisixRoute) (*translation.TranslateContext, error)
+ // TranslateSSLV2Beta3 translates the configv2beta3.ApisixTls object into the APISIX SSL resource.
+ TranslateSSLV2Beta3(*configv2beta3.ApisixTls) (*apisixv1.Ssl, error)
+ // TranslateSSLV2 translates the configv2.ApisixTls object into the APISIX SSL resource.
+ TranslateSSLV2(*configv2.ApisixTls) (*apisixv1.Ssl, error)
+ // TranslateClusterConfig translates the configv2beta3.ApisixClusterConfig object into the APISIX
+ // Global Rule resource.
+ 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.
+ 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) (*translation.TranslateContext, error)
+ // TranslatePluginConfigV2beta3NotStrictly translates the configv2beta3.ApisixPluginConfig object into several PluginConfig
+ // resources not strictly, only used for delete event.
+ TranslatePluginConfigV2beta3NotStrictly(*configv2beta3.ApisixPluginConfig) (*translation.TranslateContext, error)
+ // TranslatePluginConfigV2 translates the configv2.ApisixPluginConfig object into several PluginConfig
+ // resources.
+ TranslatePluginConfigV2(*configv2.ApisixPluginConfig) (*translation.TranslateContext, error)
+ // TranslatePluginConfigV2NotStrictly translates the configv2.ApisixPluginConfig object into several PluginConfig
+ // resources not strictly, only used for delete event.
+ TranslatePluginConfigV2NotStrictly(*configv2.ApisixPluginConfig) (*translation.TranslateContext, error)
+
+ TranslateRouteMatchExprs(nginxVars []configv2.ApisixRouteHTTPMatchExpr) ([][]apisixv1.StringOrSlice, error)
+}
+
+func NewApisixTranslator(opts *TranslatorOptions, t translation.Translator) ApisixTranslator {
+ return &translator{
+ TranslatorOptions: opts,
+ Translator: t,
+ }
+}
diff --git a/pkg/providers/controller.go b/pkg/providers/controller.go
new file mode 100644
index 00000000..1897253d
--- /dev/null
+++ b/pkg/providers/controller.go
@@ -0,0 +1,500 @@
+// 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 providers
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ "go.uber.org/zap"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/client-go/kubernetes/scheme"
+ typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/tools/cache"
+ "k8s.io/client-go/tools/leaderelection"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "k8s.io/client-go/tools/record"
+
+ "github.com/apache/apisix-ingress-controller/pkg/api"
+ "github.com/apache/apisix-ingress-controller/pkg/apisix"
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ apisixscheme "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/scheme"
+ "github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/metrics"
+ apisixprovider "github.com/apache/apisix-ingress-controller/pkg/providers/apisix"
+ apisixtranslation "github.com/apache/apisix-ingress-controller/pkg/providers/apisix/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/gateway"
+ ingressprovider "github.com/apache/apisix-ingress-controller/pkg/providers/ingress"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/pod"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
+)
+
+const (
+ // _component is used for event component
+ _component = "ApisixIngress"
+ // minimum interval for ingress sync to APISIX
+ _mininumApisixResourceSyncInterval = 60 * time.Second
+)
+
+// Controller is the ingress apisix controller object.
+type Controller struct {
+ name string
+ namespace string
+ cfg *config.Config
+ apisix apisix.APISIX
+ apiServer *api.Server
+ MetricsCollector metrics.Collector
+ kubeClient *kube.KubeClient
+ // recorder event
+ recorder record.EventRecorder
+
+ // leaderContextCancelFunc will be called when apisix-ingress-controller
+ // decides to give up its leader role.
+ leaderContextCancelFunc context.CancelFunc
+
+ translator translation.Translator
+ apisixTranslator apisixtranslation.ApisixTranslator
+
+ informers *providertypes.ListerInformer
+
+ namespaceProvider namespace.WatchingNamespaceProvider
+ podProvider pod.Provider
+ kubeProvider k8s.Provider
+ gatewayProvider *gateway.Provider
+ apisixProvider apisixprovider.Provider
+ ingressProvider ingressprovider.Provider
+}
+
+// NewController creates an ingress apisix controller object.
+func NewController(cfg *config.Config) (*Controller, error) {
+ podName := os.Getenv("POD_NAME")
+ podNamespace := os.Getenv("POD_NAMESPACE")
+ if podNamespace == "" {
+ podNamespace = "default"
+ }
+ client, err := apisix.NewClient()
+ if err != nil {
+ return nil, err
+ }
+
+ kubeClient, err := kube.NewKubeClient(cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ apiSrv, err := api.NewServer(cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ // recorder
+ utilruntime.Must(apisixscheme.AddToScheme(scheme.Scheme))
+ eventBroadcaster := record.NewBroadcaster()
+ eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeClient.Client.CoreV1().Events("")})
+
+ c := &Controller{
+ name: podName,
+ namespace: podNamespace,
+ cfg: cfg,
+ apiServer: apiSrv,
+ apisix: client,
+ MetricsCollector: metrics.NewPrometheusCollector(),
+ kubeClient: kubeClient,
+ recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: _component}),
+ }
+ return c, nil
+}
+
+// Eventf implements the resourcelock.EventRecorder interface.
+func (c *Controller) Eventf(_ runtime.Object, eventType string, reason string, message string, _ ...interface{}) {
+ log.Infow(reason, zap.String("message", message), zap.String("event_type", eventType))
+}
+
+// Run launches the controller.
+func (c *Controller) Run(stop chan struct{}) error {
+ rootCtx, rootCancel := context.WithCancel(context.Background())
+ defer rootCancel()
+ go func() {
+ <-stop
+ rootCancel()
+ }()
+ c.MetricsCollector.ResetLeader(false)
+
+ go func() {
+ if err := c.apiServer.Run(rootCtx.Done()); err != nil {
+ log.Errorf("failed to launch API Server: %s", err)
+ }
+ }()
+
+ lock := &resourcelock.LeaseLock{
+ LeaseMeta: metav1.ObjectMeta{
+ Namespace: c.namespace,
+ Name: c.cfg.Kubernetes.ElectionID,
+ },
+ Client: c.kubeClient.Client.CoordinationV1(),
+ LockConfig: resourcelock.ResourceLockConfig{
+ Identity: c.name,
+ EventRecorder: c,
+ },
+ }
+ cfg := leaderelection.LeaderElectionConfig{
+ Lock: lock,
+ LeaseDuration: 15 * time.Second,
+ RenewDeadline: 5 * time.Second,
+ RetryPeriod: 2 * time.Second,
+ Callbacks: leaderelection.LeaderCallbacks{
+ OnStartedLeading: c.run,
+ OnNewLeader: func(identity string) {
+ log.Warnf("found a new leader %s", identity)
+ if identity != c.name {
+ log.Infow("controller now is running as a candidate",
+ zap.String("namespace", c.namespace),
+ zap.String("pod", c.name),
+ )
+ c.MetricsCollector.ResetLeader(false)
+ // delete the old APISIX cluster, so that the cached state
+ // like synchronization won't be used next time the candidate
+ // becomes the leader again.
+ c.apisix.DeleteCluster(c.cfg.APISIX.DefaultClusterName)
+ }
+ },
+ OnStoppedLeading: func() {
+ log.Infow("controller now is running as a candidate",
+ zap.String("namespace", c.namespace),
+ zap.String("pod", c.name),
+ )
+ c.MetricsCollector.ResetLeader(false)
+ // delete the old APISIX cluster, so that the cached state
+ // like synchronization won't be used next time the candidate
+ // becomes the leader again.
+ c.apisix.DeleteCluster(c.cfg.APISIX.DefaultClusterName)
+ },
+ },
+ ReleaseOnCancel: true,
+ Name: "ingress-apisix",
+ }
+ elector, err := leaderelection.NewLeaderElector(cfg)
+ if err != nil {
+ log.Errorf("failed to create leader elector: %s", err.Error())
+ return err
+ }
+
+election:
+ curCtx, cancel := context.WithCancel(rootCtx)
+ c.leaderContextCancelFunc = cancel
+ elector.Run(curCtx)
+ select {
+ case <-rootCtx.Done():
+ return nil
+ default:
+ goto election
+ }
+}
+
+func (c *Controller) initSharedInformers() *providertypes.ListerInformer {
+ kubeFactory := c.kubeClient.NewSharedIndexInformerFactory()
+ apisixFactory := c.kubeClient.NewAPISIXSharedIndexInformerFactory()
+
+ epLister, epInformer := kube.NewEndpointListerAndInformer(kubeFactory, c.cfg.Kubernetes.WatchEndpointSlices)
+ svcInformer := kubeFactory.Core().V1().Services().Informer()
+ svcLister := kubeFactory.Core().V1().Services().Lister()
+
+ var (
+ apisixUpstreamInformer cache.SharedIndexInformer
+ apisixTlsInformer cache.SharedIndexInformer
+ )
+ switch c.cfg.Kubernetes.APIVersion {
+ case config.ApisixV2beta3:
+ apisixUpstreamInformer = apisixFactory.Apisix().V2beta3().ApisixUpstreams().Informer()
+ apisixTlsInformer = apisixFactory.Apisix().V2beta3().ApisixTlses().Informer()
+ case config.ApisixV2:
+ apisixUpstreamInformer = apisixFactory.Apisix().V2().ApisixUpstreams().Informer()
+ apisixTlsInformer = apisixFactory.Apisix().V2().ApisixTlses().Informer()
+ default:
+ panic(fmt.Errorf("unsupported API version %v", c.cfg.Kubernetes.APIVersion))
+ }
+
+ apisixUpstreamLister := kube.NewApisixUpstreamLister(
+ apisixFactory.Apisix().V2beta3().ApisixUpstreams().Lister(),
+ apisixFactory.Apisix().V2().ApisixUpstreams().Lister(),
+ )
+ apisixTlsLister := kube.NewApisixTlsLister(
+ apisixFactory.Apisix().V2beta3().ApisixTlses().Lister(),
+ apisixFactory.Apisix().V2().ApisixTlses().Lister(),
+ )
+
+ podInformer := kubeFactory.Core().V1().Pods().Informer()
+ podLister := kubeFactory.Core().V1().Pods().Lister()
+
+ secretInformer := kubeFactory.Core().V1().Secrets().Informer()
+ secretLister := kubeFactory.Core().V1().Secrets().Lister()
+
+ listerInformer := &providertypes.ListerInformer{
+ EpLister: epLister,
+ EpInformer: epInformer,
+ SvcLister: svcLister,
+ SvcInformer: svcInformer,
+ SecretLister: secretLister,
+ SecretInformer: secretInformer,
+ PodLister: podLister,
+ PodInformer: podInformer,
+ ApisixUpstreamLister: apisixUpstreamLister,
+ ApisixUpstreamInformer: apisixUpstreamInformer,
+ ApisixTlsLister: apisixTlsLister,
+ ApisixTlsInformer: apisixTlsInformer,
+ }
+
+ return listerInformer
+}
+
+func (c *Controller) run(ctx context.Context) {
+ log.Infow("controller tries to leading ...",
+ zap.String("namespace", c.namespace),
+ zap.String("pod", c.name),
+ )
+
+ var cancelFunc context.CancelFunc
+ ctx, cancelFunc = context.WithCancel(ctx)
+ defer cancelFunc()
+
+ // give up leader
+ defer c.leaderContextCancelFunc()
+
+ clusterOpts := &apisix.ClusterOptions{
+ Name: c.cfg.APISIX.DefaultClusterName,
+ AdminKey: c.cfg.APISIX.DefaultClusterAdminKey,
+ BaseURL: c.cfg.APISIX.DefaultClusterBaseURL,
+ MetricsCollector: c.MetricsCollector,
+ }
+ err := c.apisix.AddCluster(ctx, clusterOpts)
+ if err != nil && err != apisix.ErrDuplicatedCluster {
+ // TODO give up the leader role
+ log.Errorf("failed to add default cluster: %s", err)
+ return
+ }
+
+ if err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).HasSynced(ctx); err != nil {
+ // TODO give up the leader role
+ log.Errorf("failed to wait the default cluster to be ready: %s", err)
+
+ // re-create apisix cluster, used in next c.run
+ if err = c.apisix.UpdateCluster(ctx, clusterOpts); err != nil {
+ log.Errorf("failed to update default cluster: %s", err)
+ return
+ }
+ return
+ }
+
+ // Creation Phase
+
+ c.informers = c.initSharedInformers()
+ common := &providertypes.Common{
+ ListerInformer: c.informers,
+ Config: c.cfg,
+ APISIX: c.apisix,
+ KubeClient: c.kubeClient,
+ MetricsCollector: c.MetricsCollector,
+ Recorder: c.recorder,
+ }
+
+ c.namespaceProvider, err = namespace.NewWatchingNamespaceProvider(ctx, c.kubeClient, c.cfg)
+ if err != nil {
+ ctx.Done()
+ return
+ }
+
+ c.podProvider, err = pod.NewProvider(common, c.namespaceProvider)
+ if err != nil {
+ ctx.Done()
+ return
+ }
+
+ c.translator = translation.NewTranslator(&translation.TranslatorOptions{
+ APIVersion: c.cfg.Kubernetes.APIVersion,
+ EndpointLister: c.informers.EpLister,
+ ServiceLister: c.informers.SvcLister,
+ SecretLister: c.informers.SecretLister,
+ PodLister: c.informers.PodLister,
+ ApisixUpstreamLister: c.informers.ApisixUpstreamLister,
+ PodProvider: c.podProvider,
+ })
+
+ c.apisixProvider, c.apisixTranslator, err = apisixprovider.NewProvider(common, c.namespaceProvider, c.translator)
+ if err != nil {
+ ctx.Done()
+ return
+ }
+
+ c.kubeProvider, err = k8s.NewProvider(common, c.translator, c.namespaceProvider, c.apisixProvider)
+ if err != nil {
+ ctx.Done()
+ return
+ }
+
+ c.ingressProvider, err = ingressprovider.NewProvider(common, c.namespaceProvider, c.translator, c.apisixTranslator)
+ if err != nil {
+ ctx.Done()
+ return
+ }
+
+ if c.cfg.Kubernetes.EnableGatewayAPI {
+ c.gatewayProvider, err = gateway.NewGatewayProvider(&gateway.ProviderOptions{
+ Cfg: c.cfg,
+ APISIX: c.apisix,
+ APISIXClusterName: c.cfg.APISIX.DefaultClusterName,
+ KubeTranslator: c.translator,
+ RestConfig: nil,
+ KubeClient: c.kubeClient.Client,
+ MetricsCollector: c.MetricsCollector,
+ NamespaceProvider: c.namespaceProvider,
+ })
+ if err != nil {
+ ctx.Done()
+ return
+ }
+ }
+
+ // Init Phase
+
+ if err = c.namespaceProvider.Init(ctx); err != nil {
+ ctx.Done()
+ return
+ }
+ if err = c.apisixProvider.Init(ctx); err != nil {
+ ctx.Done()
+ return
+ }
+
+ // Run Phase
+
+ e := utils.ParallelExecutor{}
+
+ e.Add(func() {
+ c.checkClusterHealth(ctx, cancelFunc)
+ })
+
+ e.Add(func() {
+ c.informers.Run(ctx)
+ })
+
+ e.Add(func() {
+ c.namespaceProvider.Run(ctx)
+ })
+
+ e.Add(func() {
+ c.kubeProvider.Run(ctx)
+ })
+
+ e.Add(func() {
+ c.apisixProvider.Run(ctx)
+ })
+
+ e.Add(func() {
+ c.ingressProvider.Run(ctx)
+ })
+
+ if c.cfg.Kubernetes.EnableGatewayAPI {
+ e.Add(func() {
+ c.gatewayProvider.Run(ctx)
+ })
+ }
+
+ e.Add(func() {
+ c.resourceSyncLoop(ctx, c.cfg.ApisixResourceSyncInterval.Duration)
+ })
+ c.MetricsCollector.ResetLeader(true)
+
+ log.Infow("controller now is running as leader",
+ zap.String("namespace", c.namespace),
+ zap.String("pod", c.name),
+ )
+
+ <-ctx.Done()
+ e.Wait()
+
+ for _, execErr := range e.Errors() {
+ log.Error(execErr.Error())
+ }
+ if len(e.Errors()) > 0 {
+ log.Error("Start failed, abort...")
+ cancelFunc()
+ }
+}
+
+func (c *Controller) checkClusterHealth(ctx context.Context, cancelFunc context.CancelFunc) {
+ defer cancelFunc()
+ t := time.NewTicker(5 * time.Second)
+ defer t.Stop()
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-t.C:
+ }
+
+ err := c.apisix.Cluster(c.cfg.APISIX.DefaultClusterName).HealthCheck(ctx)
+ if err != nil {
+ // Finally failed health check, then give up leader.
+ log.Warnf("failed to check health for default cluster: %s, give up leader", err)
+ c.apiServer.HealthState.Lock()
+ defer c.apiServer.HealthState.Unlock()
+
+ c.apiServer.HealthState.Err = err
+ return
+ }
+ log.Debugf("success check health for default cluster")
+ c.MetricsCollector.IncrCheckClusterHealth(c.name)
+ }
+}
+
+func (c *Controller) syncAllResources() {
+ e := utils.ParallelExecutor{}
+
+ e.Add(c.ingressProvider.ResourceSync)
+ e.Add(c.apisixProvider.ResourceSync)
+
+ e.Wait()
+}
+
+func (c *Controller) resourceSyncLoop(ctx context.Context, interval time.Duration) {
+ // The interval shall not be less than 60 seconds.
+ if interval < _mininumApisixResourceSyncInterval {
+ log.Warnw("The apisix-resource-sync-interval shall not be less than 60 seconds.",
+ zap.String("apisix-resource-sync-interval", interval.String()),
+ )
+ interval = _mininumApisixResourceSyncInterval
+ }
+ ticker := time.NewTicker(interval)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ c.syncAllResources()
+ continue
+ case <-ctx.Done():
+ return
+ }
+ }
+}
diff --git a/pkg/ingress/gateway/gateway.go b/pkg/providers/gateway/gateway.go
similarity index 99%
rename from pkg/ingress/gateway/gateway.go
rename to pkg/providers/gateway/gateway.go
index 171ea14a..f6fd345b 100644
--- a/pkg/ingress/gateway/gateway.go
+++ b/pkg/providers/gateway/gateway.go
@@ -27,8 +27,8 @@ import (
"k8s.io/client-go/util/workqueue"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
diff --git a/pkg/ingress/gateway/gateway_class.go b/pkg/providers/gateway/gateway_class.go
similarity index 100%
rename from pkg/ingress/gateway/gateway_class.go
rename to pkg/providers/gateway/gateway_class.go
diff --git a/pkg/ingress/gateway/gateway_httproute.go b/pkg/providers/gateway/gateway_httproute.go
similarity index 97%
rename from pkg/ingress/gateway/gateway_httproute.go
rename to pkg/providers/gateway/gateway_httproute.go
index 3fb60ba5..92d06090 100644
--- a/pkg/ingress/gateway/gateway_httproute.go
+++ b/pkg/providers/gateway/gateway_httproute.go
@@ -24,9 +24,9 @@ import (
"k8s.io/client-go/util/workqueue"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
diff --git a/pkg/ingress/gateway/gateway_tlsroute.go b/pkg/providers/gateway/gateway_tlsroute.go
similarity index 98%
rename from pkg/ingress/gateway/gateway_tlsroute.go
rename to pkg/providers/gateway/gateway_tlsroute.go
index 52f6af05..f70da715 100644
--- a/pkg/ingress/gateway/gateway_tlsroute.go
+++ b/pkg/providers/gateway/gateway_tlsroute.go
@@ -41,9 +41,9 @@ import (
"k8s.io/client-go/util/workqueue"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
diff --git a/pkg/ingress/gateway/provider.go b/pkg/providers/gateway/provider.go
similarity index 94%
rename from pkg/ingress/gateway/provider.go
rename to pkg/providers/gateway/provider.go
index ee3cb1b0..c8305753 100644
--- a/pkg/ingress/gateway/provider.go
+++ b/pkg/providers/gateway/provider.go
@@ -32,13 +32,13 @@ import (
"github.com/apache/apisix-ingress-controller/pkg/apisix"
"github.com/apache/apisix-ingress-controller/pkg/config"
- gatewaytranslation "github.com/apache/apisix-ingress-controller/pkg/ingress/gateway/translation"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/gateway/types"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/namespace"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
"github.com/apache/apisix-ingress-controller/pkg/kube"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
"github.com/apache/apisix-ingress-controller/pkg/metrics"
+ gatewaytranslation "github.com/apache/apisix-ingress-controller/pkg/providers/gateway/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/gateway/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
)
const (
@@ -87,7 +87,7 @@ type ProviderOptions struct {
RestConfig *rest.Config
KubeClient kubernetes.Interface
MetricsCollector metrics.Collector
- NamespaceProvider namespace.WatchingProvider
+ NamespaceProvider namespace.WatchingNamespaceProvider
}
func NewGatewayProvider(opts *ProviderOptions) (*Provider, error) {
@@ -154,15 +154,12 @@ func (p *Provider) Run(ctx context.Context) {
e.Add(func() {
p.gatewayInformer.Run(ctx.Done())
})
-
e.Add(func() {
p.gatewayClassInformer.Run(ctx.Done())
})
-
e.Add(func() {
p.gatewayHTTPRouteInformer.Run(ctx.Done())
})
-
e.Add(func() {
p.gatewayTLSRouteInformer.Run(ctx.Done())
})
@@ -170,15 +167,12 @@ func (p *Provider) Run(ctx context.Context) {
e.Add(func() {
p.gatewayController.run(ctx)
})
-
e.Add(func() {
p.gatewayClassController.run(ctx)
})
-
e.Add(func() {
p.gatewayHTTPRouteController.run(ctx)
})
-
e.Add(func() {
p.gatewayTLSRouteController.run(ctx)
})
diff --git a/pkg/ingress/gateway/translation/gateway.go b/pkg/providers/gateway/translation/gateway.go
similarity index 98%
rename from pkg/ingress/gateway/translation/gateway.go
rename to pkg/providers/gateway/translation/gateway.go
index edc79854..d8a70da4 100644
--- a/pkg/ingress/gateway/translation/gateway.go
+++ b/pkg/providers/gateway/translation/gateway.go
@@ -23,8 +23,8 @@ import (
"go.uber.org/zap"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/gateway/types"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/gateway/types"
)
const (
diff --git a/pkg/ingress/gateway/translation/gateway_httproute.go b/pkg/providers/gateway/translation/gateway_httproute.go
similarity index 96%
rename from pkg/ingress/gateway/translation/gateway_httproute.go
rename to pkg/providers/gateway/translation/gateway_httproute.go
index ed73a993..e1eaa657 100644
--- a/pkg/ingress/gateway/translation/gateway_httproute.go
+++ b/pkg/providers/gateway/translation/gateway_httproute.go
@@ -26,9 +26,9 @@ import (
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
"github.com/apache/apisix-ingress-controller/pkg/id"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
@@ -92,7 +92,7 @@ func (t *translator) TranslateGatewayHTTPRouteV1Alpha2(httpRoute *gatewayv1alpha
continue
}
- ups, err := t.KubeTranslator.TranslateUpstream(ns, string(backend.Name), "", int32(*backend.Port))
+ ups, err := t.KubeTranslator.TranslateService(ns, string(backend.Name), "", int32(*backend.Port))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to translate Rules[%v].BackendRefs[%v]", i, j))
}
diff --git a/pkg/ingress/gateway/translation/gateway_httproute_test.go b/pkg/providers/gateway/translation/gateway_httproute_test.go
similarity index 99%
rename from pkg/ingress/gateway/translation/gateway_httproute_test.go
rename to pkg/providers/gateway/translation/gateway_httproute_test.go
index eec7643c..0df243d0 100644
--- a/pkg/ingress/gateway/translation/gateway_httproute_test.go
+++ b/pkg/providers/gateway/translation/gateway_httproute_test.go
@@ -31,7 +31,7 @@ import (
"github.com/apache/apisix-ingress-controller/pkg/kube"
fakeapisix "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/fake"
apisixinformers "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
diff --git a/pkg/ingress/gateway/translation/gateway_tlsroute.go b/pkg/providers/gateway/translation/gateway_tlsroute.go
similarity index 94%
rename from pkg/ingress/gateway/translation/gateway_tlsroute.go
rename to pkg/providers/gateway/translation/gateway_tlsroute.go
index 085cb92b..138cc40c 100644
--- a/pkg/ingress/gateway/translation/gateway_tlsroute.go
+++ b/pkg/providers/gateway/translation/gateway_tlsroute.go
@@ -26,9 +26,9 @@ import (
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
"github.com/apache/apisix-ingress-controller/pkg/id"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
@@ -86,7 +86,7 @@ func (t *translator) TranslateGatewayTLSRouteV1Alpha2(tlsRoute *gatewayv1alpha2.
continue
}
- ups, err := t.KubeTranslator.TranslateUpstream(ns, string(backend.Name), "", int32(*backend.Port))
+ ups, err := t.KubeTranslator.TranslateService(ns, string(backend.Name), "", int32(*backend.Port))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to translate Rules[%v].BackendRefs[%v]", i, j))
}
diff --git a/pkg/ingress/gateway/translation/translator.go b/pkg/providers/gateway/translation/translator.go
similarity index 92%
rename from pkg/ingress/gateway/translation/translator.go
rename to pkg/providers/gateway/translation/translator.go
index 4ef17e9e..c0af96f7 100644
--- a/pkg/ingress/gateway/translation/translator.go
+++ b/pkg/providers/gateway/translation/translator.go
@@ -20,8 +20,8 @@ package gateway_translation
import (
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/gateway/types"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/gateway/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
)
type TranslatorOptions struct {
diff --git a/pkg/ingress/gateway/types/types.go b/pkg/providers/gateway/types/types.go
similarity index 100%
rename from pkg/ingress/gateway/types/types.go
rename to pkg/providers/gateway/types/types.go
diff --git a/pkg/ingress/ingress.go b/pkg/providers/ingress/ingress.go
similarity index 63%
rename from pkg/ingress/ingress.go
rename to pkg/providers/ingress/ingress.go
index aea2b990..689dd0b4 100644
--- a/pkg/ingress/ingress.go
+++ b/pkg/providers/ingress/ingress.go
@@ -20,14 +20,19 @@ import (
"time"
"go.uber.org/zap"
+ apiv1 "k8s.io/api/core/v1"
+ extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
+ networkingv1 "k8s.io/api/networking/v1"
+ networkingv1beta1 "k8s.io/api/networking/v1beta1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
"github.com/apache/apisix-ingress-controller/pkg/kube"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
@@ -36,24 +41,32 @@ const (
)
type ingressController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *ingressCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ ingressLister kube.IngressLister
+ ingressInformer cache.SharedIndexInformer
}
-func (c *Controller) newIngressController() *ingressController {
- ctl := &ingressController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ingress"),
- workers: 1,
+func newIngressController(common *ingressCommon, ingressLister kube.IngressLister, ingressInformer cache.SharedIndexInformer) *ingressController {
+ c := &ingressController{
+ ingressCommon: common,
+
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "ingress"),
+ workers: 1,
+
+ ingressLister: ingressLister,
+ ingressInformer: ingressInformer,
}
c.ingressInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.OnDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.OnDelete,
})
- return ctl
+ return c
}
func (c *ingressController) run(ctx context.Context) {
@@ -61,7 +74,7 @@ func (c *ingressController) run(ctx context.Context) {
defer log.Infof("ingress controller exited")
defer c.workqueue.ShutDown()
- if !cache.WaitForCacheSync(ctx.Done(), c.controller.ingressInformer.HasSynced) {
+ if !cache.WaitForCacheSync(ctx.Done(), c.ingressInformer.HasSynced) {
log.Errorf("cache sync failed")
return
}
@@ -94,11 +107,11 @@ func (c *ingressController) sync(ctx context.Context, ev *types.Event) error {
var ing kube.Ingress
switch ingEv.GroupVersion {
case kube.IngressV1:
- ing, err = c.controller.ingressLister.V1(namespace, name)
+ ing, err = c.ingressLister.V1(namespace, name)
case kube.IngressV1beta1:
- ing, err = c.controller.ingressLister.V1beta1(namespace, name)
+ ing, err = c.ingressLister.V1beta1(namespace, name)
case kube.IngressExtensionsV1beta1:
- ing, err = c.controller.ingressLister.ExtensionsV1beta1(namespace, name)
+ ing, err = c.ingressLister.ExtensionsV1beta1(namespace, name)
default:
err = fmt.Errorf("unsupported group version %s, one of (%s/%s/%s) is expected", ingEv.GroupVersion,
kube.IngressV1, kube.IngressV1beta1, kube.IngressExtensionsV1beta1)
@@ -127,7 +140,7 @@ func (c *ingressController) sync(ctx context.Context, ev *types.Event) error {
ing = ev.Tombstone.(kube.Ingress)
}
- tctx, err := c.controller.translator.TranslateIngress(ing)
+ tctx, err := c.translator.TranslateIngress(ing)
if err != nil {
log.Errorw("failed to translate ingress",
zap.Error(err),
@@ -162,7 +175,7 @@ func (c *ingressController) sync(ctx context.Context, ev *types.Event) error {
} else if ev.Type == types.EventAdd {
added = m
} else {
- oldCtx, err := c.controller.translator.TranslateOldIngress(ingEv.OldObject)
+ oldCtx, err := c.translator.TranslateOldIngress(ingEv.OldObject)
if err != nil {
log.Errorw("failed to translate ingress",
zap.String("event", "update"),
@@ -179,7 +192,7 @@ func (c *ingressController) sync(ctx context.Context, ev *types.Event) error {
}
added, updated, deleted = m.Diff(om)
}
- if err := c.controller.syncManifests(ctx, added, updated, deleted); err != nil {
+ if err := c.SyncManifests(ctx, added, updated, deleted); err != nil {
log.Errorw("failed to sync ingress artifacts",
zap.Error(err),
)
@@ -210,11 +223,11 @@ func (c *ingressController) handleSyncErr(obj interface{}, err error) {
var ing kube.Ingress
switch event.GroupVersion {
case kube.IngressV1:
- ing, errLocal = c.controller.ingressLister.V1(namespace, name)
+ ing, errLocal = c.ingressLister.V1(namespace, name)
case kube.IngressV1beta1:
- ing, errLocal = c.controller.ingressLister.V1beta1(namespace, name)
+ ing, errLocal = c.ingressLister.V1beta1(namespace, name)
case kube.IngressExtensionsV1beta1:
- ing, errLocal = c.controller.ingressLister.ExtensionsV1beta1(namespace, name)
+ ing, errLocal = c.ingressLister.ExtensionsV1beta1(namespace, name)
}
if err == nil {
@@ -223,11 +236,11 @@ func (c *ingressController) handleSyncErr(obj interface{}, err error) {
if errLocal == nil {
switch ing.GroupVersion() {
case kube.IngressV1:
- c.controller.recordStatus(ing.V1(), _resourceSynced, nil, metav1.ConditionTrue, ing.V1().GetGeneration())
+ c.recordStatus(ing.V1(), utils.ResourceSynced, nil, metav1.ConditionTrue, ing.V1().GetGeneration())
case kube.IngressV1beta1:
- c.controller.recordStatus(ing.V1beta1(), _resourceSynced, nil, metav1.ConditionTrue, ing.V1beta1().GetGeneration())
+ c.recordStatus(ing.V1beta1(), utils.ResourceSynced, nil, metav1.ConditionTrue, ing.V1beta1().GetGeneration())
case kube.IngressExtensionsV1beta1:
- c.controller.recordStatus(ing.ExtensionsV1beta1(), _resourceSynced, nil, metav1.ConditionTrue, ing.ExtensionsV1beta1().GetGeneration())
+ c.recordStatus(ing.ExtensionsV1beta1(), utils.ResourceSynced, nil, metav1.ConditionTrue, ing.ExtensionsV1beta1().GetGeneration())
}
} else {
log.Errorw("failed to list ingress resource",
@@ -236,7 +249,7 @@ func (c *ingressController) handleSyncErr(obj interface{}, err error) {
}
}
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("ingress", "success")
+ c.MetricsCollector.IncrSyncOperation("ingress", "success")
return
}
log.Warnw("sync ingress failed, will retry",
@@ -247,11 +260,11 @@ func (c *ingressController) handleSyncErr(obj interface{}, err error) {
if errLocal == nil {
switch ing.GroupVersion() {
case kube.IngressV1:
- c.controller.recordStatus(ing.V1(), _resourceSyncAborted, err, metav1.ConditionTrue, ing.V1().GetGeneration())
+ c.recordStatus(ing.V1(), utils.ResourceSyncAborted, err, metav1.ConditionTrue, ing.V1().GetGeneration())
case kube.IngressV1beta1:
- c.controller.recordStatus(ing.V1beta1(), _resourceSyncAborted, err, metav1.ConditionTrue, ing.V1beta1().GetGeneration())
+ c.recordStatus(ing.V1beta1(), utils.ResourceSyncAborted, err, metav1.ConditionTrue, ing.V1beta1().GetGeneration())
case kube.IngressExtensionsV1beta1:
- c.controller.recordStatus(ing.ExtensionsV1beta1(), _resourceSyncAborted, err, metav1.ConditionTrue, ing.ExtensionsV1beta1().GetGeneration())
+ c.recordStatus(ing.ExtensionsV1beta1(), utils.ResourceSyncAborted, err, metav1.ConditionTrue, ing.ExtensionsV1beta1().GetGeneration())
}
} else {
log.Errorw("failed to list ingress resource",
@@ -259,7 +272,7 @@ func (c *ingressController) handleSyncErr(obj interface{}, err error) {
)
}
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("ingress", "failure")
+ c.MetricsCollector.IncrSyncOperation("ingress", "failure")
}
func (c *ingressController) onAdd(obj interface{}) {
@@ -268,7 +281,7 @@ func (c *ingressController) onAdd(obj interface{}) {
log.Errorf("found ingress resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
@@ -293,7 +306,7 @@ func (c *ingressController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("ingress", "add")
+ c.MetricsCollector.IncrEvents("ingress", "add")
}
func (c *ingressController) onUpdate(oldObj, newObj interface{}) {
@@ -308,7 +321,7 @@ func (c *ingressController) onUpdate(oldObj, newObj interface{}) {
log.Errorf("found ingress resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
valid := c.isIngressEffective(curr)
@@ -334,7 +347,7 @@ func (c *ingressController) onUpdate(oldObj, newObj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("ingress", "update")
+ c.MetricsCollector.IncrEvents("ingress", "update")
}
func (c *ingressController) OnDelete(obj interface{}) {
@@ -352,7 +365,7 @@ func (c *ingressController) OnDelete(obj interface{}) {
log.Errorf("found ingress resource with bad meta namespace key: %s", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
valid := c.isIngressEffective(ing)
@@ -375,7 +388,7 @@ func (c *ingressController) OnDelete(obj interface{}) {
Tombstone: ing,
})
- c.controller.MetricsCollector.IncrEvents("ingress", "delete")
+ c.MetricsCollector.IncrEvents("ingress", "delete")
}
func (c *ingressController) isIngressEffective(ing kube.Ingress) bool {
@@ -396,23 +409,23 @@ func (c *ingressController) isIngressEffective(ing kube.Ingress) bool {
// kubernetes.io/ingress.class takes the precedence.
if ica != "" {
- return ica == c.controller.cfg.Kubernetes.IngressClass
+ return ica == c.Kubernetes.IngressClass
}
if ic != nil {
- return *ic == c.controller.cfg.Kubernetes.IngressClass
+ return *ic == c.Kubernetes.IngressClass
}
return false
}
func (c *ingressController) ResourceSync() {
- objs := c.controller.ingressInformer.GetIndexer().List()
+ objs := c.ingressInformer.GetIndexer().List()
for _, obj := range objs {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
log.Errorw("found Ingress resource with bad meta namespace key", zap.String("error", err.Error()))
continue
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
continue
}
ing := kube.MustNewIngress(obj)
@@ -425,3 +438,81 @@ func (c *ingressController) ResourceSync() {
})
}
}
+
+// recordStatus record resources status
+func (c *ingressController) recordStatus(at interface{}, reason string, err error, status metav1.ConditionStatus, generation int64) {
+ client := c.KubeClient.Client
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *networkingv1.Ingress:
+ // set to status
+ lbips, err := c.ingressLBStatusIPs()
+ if err != nil {
+ log.Errorw("failed to get APISIX gateway external IPs",
+ zap.Error(err),
+ )
+
+ }
+
+ v.ObjectMeta.Generation = generation
+ v.Status.LoadBalancer.Ingress = lbips
+ if _, errRecord := client.NetworkingV1().Ingresses(v.Namespace).UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for IngressV1",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+
+ case *networkingv1beta1.Ingress:
+ // set to status
+ lbips, err := c.ingressLBStatusIPs()
+ if err != nil {
+ log.Errorw("failed to get APISIX gateway external IPs",
+ zap.Error(err),
+ )
+
+ }
+
+ v.ObjectMeta.Generation = generation
+ v.Status.LoadBalancer.Ingress = lbips
+ if _, errRecord := client.NetworkingV1beta1().Ingresses(v.Namespace).UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for IngressV1",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ case *extensionsv1beta1.Ingress:
+ // set to status
+ lbips, err := c.ingressLBStatusIPs()
+ if err != nil {
+ log.Errorw("failed to get APISIX gateway external IPs",
+ zap.Error(err),
+ )
+
+ }
+
+ v.ObjectMeta.Generation = generation
+ v.Status.LoadBalancer.Ingress = lbips
+ if _, errRecord := client.ExtensionsV1beta1().Ingresses(v.Namespace).UpdateStatus(context.TODO(), v, metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for IngressV1",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
+
+// ingressLBStatusIPs organizes the available addresses
+func (c *ingressController) ingressLBStatusIPs() ([]apiv1.LoadBalancerIngress, error) {
+ return utils.IngressLBStatusIPs(c.IngressPublishService, c.IngressStatusAddress, c.KubeClient.Client)
+}
diff --git a/pkg/ingress/ingress_test.go b/pkg/providers/ingress/ingress_test.go
similarity index 95%
rename from pkg/ingress/ingress_test.go
rename to pkg/providers/ingress/ingress_test.go
index d83e422a..fecd3a58 100644
--- a/pkg/ingress/ingress_test.go
+++ b/pkg/providers/ingress/ingress_test.go
@@ -25,12 +25,15 @@ import (
"github.com/apache/apisix-ingress-controller/pkg/config"
"github.com/apache/apisix-ingress-controller/pkg/kube"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
)
func TestIsIngressEffective(t *testing.T) {
c := &ingressController{
- controller: &Controller{
- cfg: config.NewDefaultConfig(),
+ ingressCommon: &ingressCommon{
+ Common: &providertypes.Common{
+ Config: config.NewDefaultConfig(),
+ },
},
}
cn := "ingress"
diff --git a/pkg/providers/ingress/provider.go b/pkg/providers/ingress/provider.go
new file mode 100644
index 00000000..b0ec707f
--- /dev/null
+++ b/pkg/providers/ingress/provider.go
@@ -0,0 +1,118 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package ingress
+
+import (
+ "context"
+
+ "k8s.io/client-go/tools/cache"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ apisixtranslation "github.com/apache/apisix-ingress-controller/pkg/providers/apisix/translation"
+ ingresstranslation "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
+)
+
+const (
+ ProviderName = "Ingress"
+)
+
+type ingressCommon struct {
+ *providertypes.Common
+
+ namespaceProvider namespace.WatchingNamespaceProvider
+ translator ingresstranslation.IngressTranslator
+}
+
+var _ Provider = (*ingressProvider)(nil)
+
+type Provider interface {
+ providertypes.Provider
+
+ ResourceSync()
+}
+
+type ingressProvider struct {
+ name string
+
+ ingressController *ingressController
+
+ ingressInformer cache.SharedIndexInformer
+}
+
+func NewProvider(common *providertypes.Common, namespaceProvider namespace.WatchingNamespaceProvider,
+ translator translation.Translator, apisixTranslator apisixtranslation.ApisixTranslator) (Provider, error) {
+ p := &ingressProvider{
+ name: ProviderName,
+ }
+
+ kubeFactory := common.KubeClient.NewSharedIndexInformerFactory()
+ switch common.Config.Kubernetes.IngressVersion {
+ case config.IngressNetworkingV1:
+ p.ingressInformer = kubeFactory.Networking().V1().Ingresses().Informer()
+ case config.IngressNetworkingV1beta1:
+ p.ingressInformer = kubeFactory.Networking().V1beta1().Ingresses().Informer()
+ default:
+ p.ingressInformer = kubeFactory.Extensions().V1beta1().Ingresses().Informer()
+ }
+ ingressLister := kube.NewIngressLister(
+ kubeFactory.Networking().V1().Ingresses().Lister(),
+ kubeFactory.Networking().V1beta1().Ingresses().Lister(),
+ kubeFactory.Extensions().V1beta1().Ingresses().Lister(),
+ )
+
+ c := &ingressCommon{
+ Common: common,
+ namespaceProvider: namespaceProvider,
+ translator: ingresstranslation.NewIngressTranslator(&ingresstranslation.TranslatorOptions{
+ Apisix: common.APISIX,
+ ClusterName: common.Config.APISIX.DefaultClusterName,
+ ServiceLister: common.SvcLister,
+ }, translator, apisixTranslator),
+ }
+
+ p.ingressController = newIngressController(c, ingressLister, p.ingressInformer)
+
+ return p, nil
+}
+
+func (p *ingressProvider) Run(ctx context.Context) {
+ e := utils.ParallelExecutor{}
+
+ e.Add(func() {
+ p.ingressInformer.Run(ctx.Done())
+ })
+
+ e.Add(func() {
+ p.ingressController.run(ctx)
+ })
+
+ e.Wait()
+}
+
+func (p *ingressProvider) ResourceSync() {
+ e := utils.ParallelExecutor{}
+
+ e.Add(p.ingressController.ResourceSync)
+
+ e.Wait()
+}
diff --git a/pkg/kube/translation/annotations.go b/pkg/providers/ingress/translation/annotations.go
similarity index 91%
rename from pkg/kube/translation/annotations.go
rename to pkg/providers/ingress/translation/annotations.go
index 434ff260..6b9d3d81 100644
--- a/pkg/kube/translation/annotations.go
+++ b/pkg/providers/ingress/translation/annotations.go
@@ -17,8 +17,8 @@ package translation
import (
"go.uber.org/zap"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation/annotations"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
apisix "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
@@ -35,7 +35,7 @@ var (
}
)
-func (t *translator) translateAnnotations(anno map[string]string) apisix.Plugins {
+func (t *translator) TranslateAnnotations(anno map[string]string) apisix.Plugins {
extractor := annotations.NewExtractor(anno)
plugins := make(apisix.Plugins)
for _, handler := range _handlers {
diff --git a/pkg/kube/translation/annotations/authorization.go b/pkg/providers/ingress/translation/annotations/authorization.go
similarity index 100%
rename from pkg/kube/translation/annotations/authorization.go
rename to pkg/providers/ingress/translation/annotations/authorization.go
diff --git a/pkg/kube/translation/annotations/cors.go b/pkg/providers/ingress/translation/annotations/cors.go
similarity index 100%
rename from pkg/kube/translation/annotations/cors.go
rename to pkg/providers/ingress/translation/annotations/cors.go
diff --git a/pkg/kube/translation/annotations/cors_test.go b/pkg/providers/ingress/translation/annotations/cors_test.go
similarity index 100%
rename from pkg/kube/translation/annotations/cors_test.go
rename to pkg/providers/ingress/translation/annotations/cors_test.go
diff --git a/pkg/kube/translation/annotations/csrf.go b/pkg/providers/ingress/translation/annotations/csrf.go
similarity index 100%
rename from pkg/kube/translation/annotations/csrf.go
rename to pkg/providers/ingress/translation/annotations/csrf.go
diff --git a/pkg/kube/translation/annotations/forward_auth.go b/pkg/providers/ingress/translation/annotations/forward_auth.go
similarity index 100%
rename from pkg/kube/translation/annotations/forward_auth.go
rename to pkg/providers/ingress/translation/annotations/forward_auth.go
diff --git a/pkg/kube/translation/annotations/forward_auth_test.go b/pkg/providers/ingress/translation/annotations/forward_auth_test.go
similarity index 100%
rename from pkg/kube/translation/annotations/forward_auth_test.go
rename to pkg/providers/ingress/translation/annotations/forward_auth_test.go
diff --git a/pkg/kube/translation/annotations/iprestriction.go b/pkg/providers/ingress/translation/annotations/iprestriction.go
similarity index 100%
rename from pkg/kube/translation/annotations/iprestriction.go
rename to pkg/providers/ingress/translation/annotations/iprestriction.go
diff --git a/pkg/kube/translation/annotations/iprestriction_test.go b/pkg/providers/ingress/translation/annotations/iprestriction_test.go
similarity index 100%
rename from pkg/kube/translation/annotations/iprestriction_test.go
rename to pkg/providers/ingress/translation/annotations/iprestriction_test.go
diff --git a/pkg/kube/translation/annotations/redirect.go b/pkg/providers/ingress/translation/annotations/redirect.go
similarity index 100%
rename from pkg/kube/translation/annotations/redirect.go
rename to pkg/providers/ingress/translation/annotations/redirect.go
diff --git a/pkg/kube/translation/annotations/rewrite.go b/pkg/providers/ingress/translation/annotations/rewrite.go
similarity index 100%
rename from pkg/kube/translation/annotations/rewrite.go
rename to pkg/providers/ingress/translation/annotations/rewrite.go
diff --git a/pkg/kube/translation/annotations/types.go b/pkg/providers/ingress/translation/annotations/types.go
similarity index 100%
rename from pkg/kube/translation/annotations/types.go
rename to pkg/providers/ingress/translation/annotations/types.go
diff --git a/pkg/kube/translation/ingress.go b/pkg/providers/ingress/translation/translator.go
similarity index 78%
rename from pkg/kube/translation/ingress.go
rename to pkg/providers/ingress/translation/translator.go
index 3c360b0b..48b2a87d 100644
--- a/pkg/kube/translation/ingress.go
+++ b/pkg/providers/ingress/translation/translator.go
@@ -1,17 +1,20 @@
-// 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
+// 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
+// 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.
//
-// 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 translation
import (
@@ -26,24 +29,80 @@ import (
networkingv1beta1 "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
+ listerscorev1 "k8s.io/client-go/listers/core/v1"
+ "github.com/apache/apisix-ingress-controller/pkg/apisix"
"github.com/apache/apisix-ingress-controller/pkg/id"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
configv2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
kubev2 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
kubev2beta3 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2beta3"
apisixconst "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/const"
- "github.com/apache/apisix-ingress-controller/pkg/kube/translation/annotations"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ apisixtranslation "github.com/apache/apisix-ingress-controller/pkg/providers/apisix/translation"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
+type TranslatorOptions struct {
+ Apisix apisix.APISIX
+ ClusterName string
+
+ ServiceLister listerscorev1.ServiceLister
+}
+
+type translator struct {
+ *TranslatorOptions
+ translation.Translator
+ ApisixTranslator apisixtranslation.ApisixTranslator
+}
+
+type IngressTranslator interface {
+ // TranslateIngress composes a couple of APISIX Routes and upstreams according
+ // to the given Ingress resource.
+ // For old objects, you cannot use TranslateIngress to build. Because it needs to parse the latest service, which will cause data inconsistency.
+ TranslateIngress(ing kube.Ingress, args ...bool) (*translation.TranslateContext, error)
+ // TranslateOldIngress get route objects from cache
+ // Build upstream and plugin_config through route
+ TranslateOldIngress(kube.Ingress) (*translation.TranslateContext, error)
+}
+
+func NewIngressTranslator(opts *TranslatorOptions,
+ commonTranslator translation.Translator, apisixTranslator apisixtranslation.ApisixTranslator) IngressTranslator {
+ t := &translator{
+ TranslatorOptions: opts,
+ Translator: commonTranslator,
+ ApisixTranslator: apisixTranslator,
+ }
+
+ return t
+}
+
+func (t *translator) TranslateIngress(ing kube.Ingress, args ...bool) (*translation.TranslateContext, error) {
+ var skipVerify = false
+ if len(args) != 0 {
+ skipVerify = args[0]
+ }
+ switch ing.GroupVersion() {
+ case kube.IngressV1:
+ return t.translateIngressV1(ing.V1(), skipVerify)
+ case kube.IngressV1beta1:
+ return t.translateIngressV1beta1(ing.V1beta1(), skipVerify)
+ case kube.IngressExtensionsV1beta1:
+ return t.translateIngressExtensionsV1beta1(ing.ExtensionsV1beta1(), skipVerify)
+ default:
+ return nil, fmt.Errorf("translator: source group version not supported: %s", ing.GroupVersion())
+ }
+}
+
const (
_regexPriority = 100
)
-func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bool) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
- plugins := t.translateAnnotations(ing.Annotations)
+func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bool) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
+ plugins := t.TranslateAnnotations(ing.Annotations)
annoExtractor := annotations.NewExtractor(ing.Annotations)
useRegex := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "use-regex")
enableWebsocket := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "enable-websocket")
@@ -69,7 +128,7 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo
Name: tls.SecretName,
Namespace: ing.Namespace,
}
- ssl, err := t.TranslateSSLV2(&apisixTls)
+ ssl, err := t.ApisixTranslator.TranslateSSLV2(&apisixTls)
if err != nil {
log.Errorw("failed to translate ingress tls to apisix tls",
zap.Error(err),
@@ -138,7 +197,7 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo
route.Uris = uris
route.EnableWebsocket = enableWebsocket
if len(nginxVars) > 0 {
- routeVars, err := t.translateRouteMatchExprs(nginxVars)
+ routeVars, err := t.ApisixTranslator.TranslateRouteMatchExprs(nginxVars)
if err != nil {
return nil, err
}
@@ -161,9 +220,9 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo
return ctx, nil
}
-func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, skipVerify bool) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
- plugins := t.translateAnnotations(ing.Annotations)
+func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, skipVerify bool) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
+ plugins := t.TranslateAnnotations(ing.Annotations)
annoExtractor := annotations.NewExtractor(ing.Annotations)
useRegex := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "use-regex")
enableWebsocket := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "enable-websocket")
@@ -189,7 +248,7 @@ func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, ski
Name: tls.SecretName,
Namespace: ing.Namespace,
}
- ssl, err := t.TranslateSSLV2Beta3(&apisixTls)
+ ssl, err := t.ApisixTranslator.TranslateSSLV2Beta3(&apisixTls)
if err != nil {
log.Errorw("failed to translate ingress tls to apisix tls",
zap.Error(err),
@@ -258,7 +317,7 @@ func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, ski
route.Uris = uris
route.EnableWebsocket = enableWebsocket
if len(nginxVars) > 0 {
- routeVars, err := t.translateRouteMatchExprs(nginxVars)
+ routeVars, err := t.ApisixTranslator.TranslateRouteMatchExprs(nginxVars)
if err != nil {
return nil, err
}
@@ -318,15 +377,15 @@ func (t *translator) translateUpstreamFromIngressV1(namespace string, backend *n
}
}
if svcPort == 0 {
- return nil, &translateError{
- field: "service",
- reason: "port not found",
+ return nil, &translation.TranslateError{
+ Field: "service",
+ Reason: "port not found",
}
}
} else {
svcPort = backend.Port.Number
}
- ups, err := t.TranslateUpstream(namespace, backend.Name, "", svcPort)
+ ups, err := t.TranslateService(namespace, backend.Name, "", svcPort)
if err != nil {
return nil, err
}
@@ -335,9 +394,9 @@ func (t *translator) translateUpstreamFromIngressV1(namespace string, backend *n
return ups, nil
}
-func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.Ingress, skipVerify bool) (*TranslateContext, error) {
- ctx := DefaultEmptyTranslateContext()
- plugins := t.translateAnnotations(ing.Annotations)
+func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.Ingress, skipVerify bool) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
+ plugins := t.TranslateAnnotations(ing.Annotations)
annoExtractor := annotations.NewExtractor(ing.Annotations)
useRegex := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "use-regex")
enableWebsocket := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "enable-websocket")
@@ -403,7 +462,7 @@ func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.In
route.Uris = uris
route.EnableWebsocket = enableWebsocket
if len(nginxVars) > 0 {
- routeVars, err := t.translateRouteMatchExprs(nginxVars)
+ routeVars, err := t.ApisixTranslator.TranslateRouteMatchExprs(nginxVars)
if err != nil {
return nil, err
}
@@ -464,15 +523,15 @@ func (t *translator) translateUpstreamFromIngressV1beta1(namespace string, svcNa
}
}
if portNumber == 0 {
- return nil, &translateError{
- field: "service",
- reason: "port not found",
+ return nil, &translation.TranslateError{
+ Field: "service",
+ Reason: "port not found",
}
}
} else {
portNumber = svcPort.IntVal
}
- ups, err := t.TranslateUpstream(namespace, svcName, "", portNumber)
+ ups, err := t.TranslateService(namespace, svcName, "", portNumber)
if err != nil {
return nil, err
}
@@ -481,8 +540,21 @@ func (t *translator) translateUpstreamFromIngressV1beta1(namespace string, svcNa
return ups, nil
}
-func (t *translator) translateOldIngressV1(ing *networkingv1.Ingress) (*TranslateContext, error) {
- oldCtx := DefaultEmptyTranslateContext()
+func (t *translator) TranslateOldIngress(ing kube.Ingress) (*translation.TranslateContext, error) {
+ switch ing.GroupVersion() {
+ case kube.IngressV1:
+ return t.translateOldIngressV1(ing.V1())
+ case kube.IngressV1beta1:
+ return t.translateOldIngressV1beta1(ing.V1beta1())
+ case kube.IngressExtensionsV1beta1:
+ return t.translateOldIngressExtensionsv1beta1(ing.ExtensionsV1beta1())
+ default:
+ return nil, fmt.Errorf("translator: source group version not supported: %s", ing.GroupVersion())
+ }
+}
+
+func (t *translator) translateOldIngressV1(ing *networkingv1.Ingress) (*translation.TranslateContext, error) {
+ oldCtx := translation.DefaultEmptyTranslateContext()
for _, tls := range ing.Spec.TLS {
apisixTls := configv2.ApisixTls{
@@ -503,7 +575,7 @@ func (t *translator) translateOldIngressV1(ing *networkingv1.Ingress) (*Translat
Name: tls.SecretName,
Namespace: ing.Namespace,
}
- ssl, err := t.TranslateSSLV2(&apisixTls)
+ ssl, err := t.ApisixTranslator.TranslateSSLV2(&apisixTls)
if err != nil {
log.Debugw("failed to translate ingress tls to apisix tls",
zap.Error(err),
@@ -536,8 +608,8 @@ func (t *translator) translateOldIngressV1(ing *networkingv1.Ingress) (*Translat
return oldCtx, nil
}
-func (t *translator) translateOldIngressV1beta1(ing *networkingv1beta1.Ingress) (*TranslateContext, error) {
- oldCtx := DefaultEmptyTranslateContext()
+func (t *translator) translateOldIngressV1beta1(ing *networkingv1beta1.Ingress) (*translation.TranslateContext, error) {
+ oldCtx := translation.DefaultEmptyTranslateContext()
for _, tls := range ing.Spec.TLS {
apisixTls := configv2.ApisixTls{
@@ -558,7 +630,7 @@ func (t *translator) translateOldIngressV1beta1(ing *networkingv1beta1.Ingress)
Name: tls.SecretName,
Namespace: ing.Namespace,
}
- ssl, err := t.TranslateSSLV2(&apisixTls)
+ ssl, err := t.ApisixTranslator.TranslateSSLV2(&apisixTls)
if err != nil {
continue
}
@@ -587,8 +659,8 @@ func (t *translator) translateOldIngressV1beta1(ing *networkingv1beta1.Ingress)
return oldCtx, nil
}
-func (t *translator) translateOldIngressExtensionsv1beta1(ing *extensionsv1beta1.Ingress) (*TranslateContext, error) {
- oldCtx := DefaultEmptyTranslateContext()
+func (t *translator) translateOldIngressExtensionsv1beta1(ing *extensionsv1beta1.Ingress) (*translation.TranslateContext, error) {
+ oldCtx := translation.DefaultEmptyTranslateContext()
for _, tls := range ing.Spec.TLS {
apisixTls := configv2.ApisixTls{
@@ -609,7 +681,7 @@ func (t *translator) translateOldIngressExtensionsv1beta1(ing *extensionsv1beta1
Name: tls.SecretName,
Namespace: ing.Namespace,
}
- ssl, err := t.TranslateSSLV2(&apisixTls)
+ ssl, err := t.ApisixTranslator.TranslateSSLV2(&apisixTls)
if err != nil {
continue
}
diff --git a/pkg/providers/k8s/endpoint/base.go b/pkg/providers/k8s/endpoint/base.go
new file mode 100644
index 00000000..ac67aa87
--- /dev/null
+++ b/pkg/providers/k8s/endpoint/base.go
@@ -0,0 +1,133 @@
+// 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 endpoint
+
+import (
+ "context"
+ "fmt"
+
+ "go.uber.org/zap"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ listerscorev1 "k8s.io/client-go/listers/core/v1"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ 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"
+ "github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
+ apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+type baseEndpointController struct {
+ *providertypes.Common
+ translator translation.Translator
+
+ apisixUpstreamLister kube.ApisixUpstreamLister
+ svcLister listerscorev1.ServiceLister
+}
+
+func (c *baseEndpointController) syncEndpoint(ctx context.Context, ep kube.Endpoint) error {
+ log.Debugw("endpoint controller syncing endpoint",
+ zap.Any("endpoint", ep),
+ )
+
+ namespace, err := ep.Namespace()
+ if err != nil {
+ return err
+ }
+ svcName := ep.ServiceName()
+ svc, err := c.svcLister.Services(namespace).Get(svcName)
+ if err != nil {
+ if k8serrors.IsNotFound(err) {
+ log.Infof("service %s/%s not found", namespace, svcName)
+ return nil
+ }
+ log.Errorf("failed to get service %s/%s: %s", namespace, svcName, err)
+ return err
+ }
+
+ switch c.Kubernetes.APIVersion {
+ case config.ApisixV2beta3:
+ var subsets []configv2beta3.ApisixUpstreamSubset
+ subsets = append(subsets, configv2beta3.ApisixUpstreamSubset{})
+ auKube, err := c.apisixUpstreamLister.V2beta3(namespace, svcName)
+ if err != nil {
+ if !k8serrors.IsNotFound(err) {
+ log.Errorf("failed to get ApisixUpstream %s/%s: %s", namespace, svcName, err)
+ return err
+ }
+ } else if auKube.V2beta3().Spec != nil && len(auKube.V2beta3().Spec.Subsets) > 0 {
+ subsets = append(subsets, auKube.V2beta3().Spec.Subsets...)
+ }
+ clusters := c.APISIX.ListClusters()
+ for _, port := range svc.Spec.Ports {
+ for _, subset := range subsets {
+ nodes, err := c.translator.TranslateEndpoint(ep, port.Port, subset.Labels)
+ if err != nil {
+ log.Errorw("failed to translate upstream nodes",
+ zap.Error(err),
+ zap.Any("endpoints", ep),
+ zap.Int32("port", port.Port),
+ )
+ }
+ name := apisixv1.ComposeUpstreamName(namespace, svcName, subset.Name, port.Port)
+ for _, cluster := range clusters {
+ if err := c.SyncUpstreamNodesChangeToCluster(ctx, cluster, nodes, name); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ case config.ApisixV2:
+ var subsets []configv2.ApisixUpstreamSubset
+ subsets = append(subsets, configv2.ApisixUpstreamSubset{})
+ auKube, err := c.apisixUpstreamLister.V2(namespace, svcName)
+ if err != nil {
+ if !k8serrors.IsNotFound(err) {
+ log.Errorf("failed to get ApisixUpstream %s/%s: %s", namespace, svcName, err)
+ return err
+ }
+ } else if auKube.V2().Spec != nil && len(auKube.V2().Spec.Subsets) > 0 {
+ subsets = append(subsets, auKube.V2().Spec.Subsets...)
+ }
+ clusters := c.APISIX.ListClusters()
+ for _, port := range svc.Spec.Ports {
+ for _, subset := range subsets {
+ nodes, err := c.translator.TranslateEndpoint(ep, port.Port, subset.Labels)
+ if err != nil {
+ log.Errorw("failed to translate upstream nodes",
+ zap.Error(err),
+ zap.Any("endpoints", ep),
+ zap.Int32("port", port.Port),
+ )
+ }
+ name := apisixv1.ComposeUpstreamName(namespace, svcName, subset.Name, port.Port)
+ for _, cluster := range clusters {
+ if err := c.SyncUpstreamNodesChangeToCluster(ctx, cluster, nodes, name); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ default:
+ panic(fmt.Errorf("unsupported ApisixUpstream version %v", c.Kubernetes.APIVersion))
+ }
+ return nil
+}
diff --git a/pkg/ingress/endpoint.go b/pkg/providers/k8s/endpoint/endpoint.go
similarity index 75%
rename from pkg/ingress/endpoint.go
rename to pkg/providers/k8s/endpoint/endpoint.go
index a3c62ff0..9b14bf12 100644
--- a/pkg/ingress/endpoint.go
+++ b/pkg/providers/k8s/endpoint/endpoint.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package endpoint
import (
"context"
@@ -26,24 +26,37 @@ import (
"github.com/apache/apisix-ingress-controller/pkg/kube"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
"github.com/apache/apisix-ingress-controller/pkg/types"
v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
type endpointsController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *baseEndpointController
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ namespaceProvider namespace.WatchingNamespaceProvider
+
+ epInformer cache.SharedIndexInformer
+ epLister kube.EndpointLister
}
-func (c *Controller) newEndpointsController() *endpointsController {
+func newEndpointsController(base *baseEndpointController, namespaceProvider namespace.WatchingNamespaceProvider) *endpointsController {
ctl := &endpointsController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "endpoints"),
- workers: 1,
+ baseEndpointController: base,
+
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second, 60*time.Second, 5), "endpoints"),
+ workers: 1,
+
+ namespaceProvider: namespaceProvider,
+
+ epLister: base.EpLister,
+ epInformer: base.EpInformer,
}
- ctl.controller.epInformer.AddEventHandler(
+ ctl.epInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
AddFunc: ctl.onAdd,
UpdateFunc: ctl.onUpdate,
@@ -59,7 +72,7 @@ func (c *endpointsController) run(ctx context.Context) {
defer log.Info("endpoints controller exited")
defer c.workqueue.ShutDown()
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.epInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.epInformer.HasSynced); !ok {
log.Error("informers sync failed")
return
}
@@ -91,8 +104,8 @@ func (c *endpointsController) sync(ctx context.Context, ev *types.Event) error {
return err
}
if ev.Type == types.EventDelete {
- clusterName := c.controller.cfg.APISIX.DefaultClusterName
- err = c.controller.apisix.Cluster(clusterName).UpstreamServiceRelation().Delete(ctx,
+ clusterName := c.Config.APISIX.DefaultClusterName
+ err = c.APISIX.Cluster(clusterName).UpstreamServiceRelation().Delete(ctx,
&v1.UpstreamServiceRelation{
ServiceName: ns + "_" + ep.ServiceName(),
})
@@ -100,20 +113,20 @@ func (c *endpointsController) sync(ctx context.Context, ev *types.Event) error {
return err
}
}
- newestEp, err := c.controller.epLister.GetEndpoint(ns, ep.ServiceName())
+ newestEp, err := c.epLister.GetEndpoint(ns, ep.ServiceName())
if err != nil {
if !errors.IsNotFound(err) {
return err
}
newestEp = ep
}
- return c.controller.syncEndpoint(ctx, newestEp)
+ return c.syncEndpoint(ctx, newestEp)
}
func (c *endpointsController) handleSyncErr(obj interface{}, err error) {
if err == nil {
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("endpoints", "success")
+ c.MetricsCollector.IncrSyncOperation("endpoints", "success")
return
}
event := obj.(*types.Event)
@@ -129,7 +142,7 @@ func (c *endpointsController) handleSyncErr(obj interface{}, err error) {
zap.Any("object", obj),
)
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("endpoints", "failure")
+ c.MetricsCollector.IncrSyncOperation("endpoints", "failure")
}
func (c *endpointsController) onAdd(obj interface{}) {
@@ -138,7 +151,7 @@ func (c *endpointsController) onAdd(obj interface{}) {
log.Errorf("found endpoints object with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("endpoints add event arrived",
@@ -150,7 +163,7 @@ func (c *endpointsController) onAdd(obj interface{}) {
Object: kube.NewEndpoint(obj.(*corev1.Endpoints)),
})
- c.controller.MetricsCollector.IncrEvents("endpoints", "add")
+ c.MetricsCollector.IncrEvents("endpoints", "add")
}
func (c *endpointsController) onUpdate(prev, curr interface{}) {
@@ -165,7 +178,7 @@ func (c *endpointsController) onUpdate(prev, curr interface{}) {
log.Errorf("found endpoints object with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("endpoints update event arrived",
@@ -178,7 +191,7 @@ func (c *endpointsController) onUpdate(prev, curr interface{}) {
Object: kube.NewEndpoint(currEp),
})
- c.controller.MetricsCollector.IncrEvents("endpoints", "update")
+ c.MetricsCollector.IncrEvents("endpoints", "update")
}
func (c *endpointsController) onDelete(obj interface{}) {
@@ -195,7 +208,7 @@ func (c *endpointsController) onDelete(obj interface{}) {
// FIXME Refactor Controller.isWatchingNamespace to just use
// namespace after all controllers use the same way to fetch
// the object.
- if !c.controller.isWatchingNamespace(ep.Namespace + "/" + ep.Name) {
+ if !c.namespaceProvider.IsWatchingNamespace(ep.Namespace + "/" + ep.Name) {
return
}
log.Debugw("endpoints delete event arrived",
@@ -206,5 +219,5 @@ func (c *endpointsController) onDelete(obj interface{}) {
Object: kube.NewEndpoint(ep),
})
- c.controller.MetricsCollector.IncrEvents("endpoints", "delete")
+ c.MetricsCollector.IncrEvents("endpoints", "delete")
}
diff --git a/pkg/ingress/endpointslice.go b/pkg/providers/k8s/endpoint/endpointslice.go
similarity index 76%
rename from pkg/ingress/endpointslice.go
rename to pkg/providers/k8s/endpoint/endpointslice.go
index 63bd05d3..56faffbf 100644
--- a/pkg/ingress/endpointslice.go
+++ b/pkg/providers/k8s/endpoint/endpointslice.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package endpoint
import (
"context"
@@ -24,7 +24,9 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
"github.com/apache/apisix-ingress-controller/pkg/types"
v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
@@ -39,27 +41,39 @@ type endpointSliceEvent struct {
}
type endpointSliceController struct {
- controller *Controller
- workqueue workqueue.RateLimitingInterface
- workers int
+ *baseEndpointController
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+
+ namespaceProvider namespace.WatchingNamespaceProvider
+
+ epInformer cache.SharedIndexInformer
+ epLister kube.EndpointLister
}
-func (c *Controller) newEndpointSliceController() *endpointSliceController {
- ctl := &endpointSliceController{
- controller: c,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(time.Second, 60*time.Second, 5), "endpointSlice"),
- workers: 1,
+func newEndpointSliceController(base *baseEndpointController, namespaceProvider namespace.WatchingNamespaceProvider) *endpointSliceController {
+ c := &endpointSliceController{
+ baseEndpointController: base,
+
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(time.Second, 60*time.Second, 5), "endpointSlice"),
+ workers: 1,
+
+ namespaceProvider: namespaceProvider,
+
+ epLister: base.EpLister,
+ epInformer: base.EpInformer,
}
- ctl.controller.epInformer.AddEventHandler(
+ c.epInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
- AddFunc: ctl.onAdd,
- UpdateFunc: ctl.onUpdate,
- DeleteFunc: ctl.onDelete,
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
},
)
- return ctl
+ return c
}
func (c *endpointSliceController) run(ctx context.Context) {
@@ -67,7 +81,7 @@ func (c *endpointSliceController) run(ctx context.Context) {
defer log.Info("endpointSlice controller exited")
defer c.workqueue.ShutDown()
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.epInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.epInformer.HasSynced); !ok {
log.Error("informers sync failed")
return
}
@@ -93,6 +107,9 @@ func (c *endpointSliceController) run(ctx context.Context) {
}
func (c *endpointSliceController) sync(ctx context.Context, ev *types.Event) error {
+ log.Debugw("process endpoint slice event",
+ zap.Any("event", ev),
+ )
epEvent := ev.Object.(endpointSliceEvent)
namespace, _, err := cache.SplitMetaNamespaceKey(epEvent.Key)
if err != nil {
@@ -102,8 +119,8 @@ func (c *endpointSliceController) sync(ctx context.Context, ev *types.Event) err
if ev.Type == types.EventDelete {
log.Debugw("endpointsplice upstream serviece sync",
zap.String("service_name", epEvent.ServiceName))
- clusterName := c.controller.cfg.APISIX.DefaultClusterName
- err = c.controller.apisix.Cluster(clusterName).UpstreamServiceRelation().Delete(ctx,
+ clusterName := c.Config.APISIX.DefaultClusterName
+ err = c.APISIX.Cluster(clusterName).UpstreamServiceRelation().Delete(ctx,
&v1.UpstreamServiceRelation{
ServiceName: namespace + "_" + epEvent.ServiceName,
})
@@ -111,19 +128,19 @@ func (c *endpointSliceController) sync(ctx context.Context, ev *types.Event) err
return err
}
}
- ep, err := c.controller.epLister.GetEndpoint(namespace, epEvent.ServiceName)
+ ep, err := c.epLister.GetEndpoint(namespace, epEvent.ServiceName)
if err != nil {
log.Errorf("failed to get all endpointSlices for service %s: %s",
epEvent.ServiceName, err)
return err
}
- return c.controller.syncEndpoint(ctx, ep)
+ return c.syncEndpoint(ctx, ep)
}
func (c *endpointSliceController) handleSyncErr(obj interface{}, err error) {
if err == nil {
c.workqueue.Forget(obj)
- c.controller.MetricsCollector.IncrSyncOperation("endpointSlice", "success")
+ c.MetricsCollector.IncrSyncOperation("endpointSlice", "success")
return
}
event := obj.(*types.Event)
@@ -139,7 +156,7 @@ func (c *endpointSliceController) handleSyncErr(obj interface{}, err error) {
zap.Any("object", obj),
)
c.workqueue.AddRateLimited(obj)
- c.controller.MetricsCollector.IncrSyncOperation("endpointSlice", "failure")
+ c.MetricsCollector.IncrSyncOperation("endpointSlice", "failure")
}
func (c *endpointSliceController) onAdd(obj interface{}) {
@@ -147,7 +164,7 @@ func (c *endpointSliceController) onAdd(obj interface{}) {
if err != nil {
log.Errorf("found endpointSlice object with bad namespace")
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
ep := obj.(*discoveryv1.EndpointSlice)
@@ -173,7 +190,7 @@ func (c *endpointSliceController) onAdd(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("endpointSlice", "add")
+ c.MetricsCollector.IncrEvents("endpointSlice", "add")
}
func (c *endpointSliceController) onUpdate(prev, curr interface{}) {
@@ -188,7 +205,7 @@ func (c *endpointSliceController) onUpdate(prev, curr interface{}) {
log.Errorf("found endpointSlice object with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
if currEp.Labels[discoveryv1.LabelManagedBy] != _endpointSlicesManagedBy {
@@ -214,7 +231,7 @@ func (c *endpointSliceController) onUpdate(prev, curr interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("endpointSlice", "update")
+ c.MetricsCollector.IncrEvents("endpointSlice", "update")
}
func (c *endpointSliceController) onDelete(obj interface{}) {
@@ -232,7 +249,7 @@ func (c *endpointSliceController) onDelete(obj interface{}) {
log.Errorf("found endpointSlice object with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
if ep.Labels[discoveryv1.LabelManagedBy] != _endpointSlicesManagedBy {
@@ -252,5 +269,5 @@ func (c *endpointSliceController) onDelete(obj interface{}) {
},
})
- c.controller.MetricsCollector.IncrEvents("endpointSlice", "delete")
+ c.MetricsCollector.IncrEvents("endpointSlice", "delete")
}
diff --git a/pkg/providers/k8s/endpoint/provider.go b/pkg/providers/k8s/endpoint/provider.go
new file mode 100644
index 00000000..8e5333e6
--- /dev/null
+++ b/pkg/providers/k8s/endpoint/provider.go
@@ -0,0 +1,77 @@
+// 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 endpoint
+
+import (
+ "context"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
+)
+
+var _ Provider = (*endpointProvider)(nil)
+
+type Provider interface {
+ providertypes.Provider
+}
+
+type endpointProvider struct {
+ cfg *config.Config
+
+ endpointsController *endpointsController
+ endpointSliceController *endpointSliceController
+}
+
+func NewProvider(common *providertypes.Common, translator translation.Translator, namespaceProvider namespace.WatchingNamespaceProvider) (Provider, error) {
+ p := &endpointProvider{
+ cfg: common.Config,
+ }
+
+ base := &baseEndpointController{
+ Common: common,
+ translator: translator,
+
+ svcLister: common.SvcLister,
+ apisixUpstreamLister: common.ApisixUpstreamLister,
+ }
+
+ if common.Kubernetes.WatchEndpointSlices {
+ p.endpointSliceController = newEndpointSliceController(base, namespaceProvider)
+ } else {
+ p.endpointsController = newEndpointsController(base, namespaceProvider)
+ }
+
+ return p, nil
+}
+
+func (p *endpointProvider) Run(ctx context.Context) {
+ e := utils.ParallelExecutor{}
+
+ e.Add(func() {
+ if p.cfg.Kubernetes.WatchEndpointSlices {
+ p.endpointSliceController.run(ctx)
+ } else {
+ p.endpointsController.run(ctx)
+ }
+ })
+
+ e.Wait()
+}
diff --git a/pkg/ingress/namespace/namespace.go b/pkg/providers/k8s/namespace/namespace.go
similarity index 100%
rename from pkg/ingress/namespace/namespace.go
rename to pkg/providers/k8s/namespace/namespace.go
diff --git a/pkg/ingress/namespace/provider.go b/pkg/providers/k8s/namespace/namespace_provider.go
similarity index 90%
rename from pkg/ingress/namespace/provider.go
rename to pkg/providers/k8s/namespace/namespace_provider.go
index e8f442dd..b4a69e92 100644
--- a/pkg/ingress/namespace/provider.go
+++ b/pkg/providers/k8s/namespace/namespace_provider.go
@@ -31,19 +31,23 @@ import (
"github.com/apache/apisix-ingress-controller/pkg/api/validation"
"github.com/apache/apisix-ingress-controller/pkg/config"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/utils"
"github.com/apache/apisix-ingress-controller/pkg/kube"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ provider "github.com/apache/apisix-ingress-controller/pkg/providers/types"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
-type WatchingProvider interface {
- Run(ctx context.Context)
+type WatchingNamespaceProvider interface {
+ provider.Provider
+
+ Init(ctx context.Context) error
+
IsWatchingNamespace(key string) bool
WatchingNamespaces() []string
}
-func NewWatchingProvider(ctx context.Context, kube *kube.KubeClient, cfg *config.Config) (WatchingProvider, error) {
+func NewWatchingNamespaceProvider(ctx context.Context, kube *kube.KubeClient, cfg *config.Config) (WatchingNamespaceProvider, error) {
var (
watchingNamespaces = new(sync.Map)
watchingLabels = make(map[string]string)
@@ -90,10 +94,6 @@ func NewWatchingProvider(ctx context.Context, kube *kube.KubeClient, cfg *config
c.controller = newNamespaceController(c)
- err := c.initWatchingNamespacesByLabels(ctx)
- if err != nil {
- return nil, err
- }
return c, nil
}
@@ -110,6 +110,14 @@ type watchingProvider struct {
controller *namespaceController
}
+func (c *watchingProvider) Init(ctx context.Context) error {
+ err := c.initWatchingNamespacesByLabels(ctx)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
func (c *watchingProvider) initWatchingNamespacesByLabels(ctx context.Context) error {
labelSelector := metav1.LabelSelector{MatchLabels: c.watchingLabels}
opts := metav1.ListOptions{
diff --git a/pkg/ingress/namespace/provider_mock.go b/pkg/providers/k8s/namespace/namespace_provider_mock.go
similarity index 89%
rename from pkg/ingress/namespace/provider_mock.go
rename to pkg/providers/k8s/namespace/namespace_provider_mock.go
index e211d400..45641cf6 100644
--- a/pkg/ingress/namespace/provider_mock.go
+++ b/pkg/providers/k8s/namespace/namespace_provider_mock.go
@@ -23,7 +23,7 @@ import (
"k8s.io/client-go/tools/cache"
)
-func NewMockWatchingProvider(namespaces []string) WatchingProvider {
+func NewMockWatchingNamespaceProvider(namespaces []string) WatchingNamespaceProvider {
return &mockWatchingProvider{
namespaces: namespaces,
}
@@ -33,6 +33,10 @@ type mockWatchingProvider struct {
namespaces []string
}
+func (c *mockWatchingProvider) Init(ctx context.Context) error {
+ return nil
+}
+
func (c *mockWatchingProvider) Run(ctx context.Context) {
}
diff --git a/pkg/ingress/pod.go b/pkg/providers/k8s/pod/pod.go
similarity index 70%
rename from pkg/ingress/pod.go
rename to pkg/providers/k8s/pod/pod.go
index fb780678..f0a36c75 100644
--- a/pkg/ingress/pod.go
+++ b/pkg/providers/k8s/pod/pod.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package pod
import (
"context"
@@ -22,18 +22,31 @@ import (
"k8s.io/client-go/tools/cache"
"github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
type podController struct {
- controller *Controller
+ *providertypes.Common
+
+ namespaceProvider namespace.WatchingNamespaceProvider
+ podInformer cache.SharedIndexInformer
+
+ podCache types.PodCache
}
-func (c *Controller) newPodController() *podController {
+func newPodController(common *providertypes.Common, nsProvider namespace.WatchingNamespaceProvider,
+ podInformer cache.SharedIndexInformer) *podController {
ctl := &podController{
- controller: c,
+ Common: common,
+
+ namespaceProvider: nsProvider,
+ podInformer: podInformer,
+
+ podCache: types.NewPodCache(),
}
- ctl.controller.podInformer.AddEventHandler(
+ ctl.podInformer.AddEventHandler(
cache.ResourceEventHandlerFuncs{
AddFunc: ctl.onAdd,
UpdateFunc: ctl.onUpdate,
@@ -47,7 +60,7 @@ func (c *podController) run(ctx context.Context) {
log.Info("pod controller started")
defer log.Info("pod controller exited")
- if ok := cache.WaitForCacheSync(ctx.Done(), c.controller.podInformer.HasSynced); !ok {
+ if ok := cache.WaitForCacheSync(ctx.Done(), c.podInformer.HasSynced); !ok {
log.Error("informers sync failed")
return
}
@@ -61,14 +74,14 @@ func (c *podController) onAdd(obj interface{}) {
log.Errorf("found pod with bad namespace/name: %s, ignore it", err)
return
}
- if !c.controller.isWatchingNamespace(key) {
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
return
}
log.Debugw("pod add event arrived",
zap.String("obj.key", key),
)
pod := obj.(*corev1.Pod)
- if err := c.controller.podCache.Add(pod); err != nil {
+ if err := c.podCache.Add(pod); err != nil {
if err == types.ErrPodNoAssignedIP {
log.Debugw("pod no assigned ip, postpone the adding in subsequent update event",
zap.Any("pod", pod),
@@ -81,7 +94,7 @@ func (c *podController) onAdd(obj interface{}) {
}
}
- c.controller.MetricsCollector.IncrEvents("pod", "add")
+ c.MetricsCollector.IncrEvents("pod", "add")
}
func (c *podController) onUpdate(oldObj, newObj interface{}) {
@@ -91,7 +104,7 @@ func (c *podController) onUpdate(oldObj, newObj interface{}) {
return
}
- if !c.controller.isWatchingNamespace(curr.Namespace + "/" + curr.Name) {
+ if !c.namespaceProvider.IsWatchingNamespace(curr.Namespace + "/" + curr.Name) {
return
}
log.Debugw("pod update event arrived",
@@ -99,7 +112,7 @@ func (c *podController) onUpdate(oldObj, newObj interface{}) {
zap.Any("pod name", curr.Name),
)
if curr.DeletionTimestamp != nil {
- if err := c.controller.podCache.Delete(curr); err != nil {
+ if err := c.podCache.Delete(curr); err != nil {
log.Errorw("failed to delete pod from cache",
zap.Error(err),
zap.Any("pod", curr),
@@ -107,7 +120,7 @@ func (c *podController) onUpdate(oldObj, newObj interface{}) {
}
}
if curr.Status.PodIP != "" {
- if err := c.controller.podCache.Add(curr); err != nil {
+ if err := c.podCache.Add(curr); err != nil {
log.Errorw("failed to add pod to cache",
zap.Error(err),
zap.Any("pod", curr),
@@ -115,7 +128,7 @@ func (c *podController) onUpdate(oldObj, newObj interface{}) {
}
}
- c.controller.MetricsCollector.IncrEvents("pod", "update")
+ c.MetricsCollector.IncrEvents("pod", "update")
}
func (c *podController) onDelete(obj interface{}) {
@@ -129,18 +142,18 @@ func (c *podController) onDelete(obj interface{}) {
pod = tombstone.Obj.(*corev1.Pod)
}
- if !c.controller.isWatchingNamespace(pod.Namespace + "/" + pod.Name) {
+ if !c.namespaceProvider.IsWatchingNamespace(pod.Namespace + "/" + pod.Name) {
return
}
log.Debugw("pod delete event arrived",
zap.Any("final state", pod),
)
- if err := c.controller.podCache.Delete(pod); err != nil {
+ if err := c.podCache.Delete(pod); err != nil {
log.Errorw("failed to delete pod from cache",
zap.Error(err),
zap.Any("pod", pod),
)
}
- c.controller.MetricsCollector.IncrEvents("pod", "delete")
+ c.MetricsCollector.IncrEvents("pod", "delete")
}
diff --git a/pkg/ingress/pod_test.go b/pkg/providers/k8s/pod/pod_test.go
similarity index 68%
rename from pkg/ingress/pod_test.go
rename to pkg/providers/k8s/pod/pod_test.go
index 4235703c..090c4a9a 100644
--- a/pkg/ingress/pod_test.go
+++ b/pkg/providers/k8s/pod/pod_test.go
@@ -12,7 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package ingress
+package pod
import (
"testing"
@@ -22,19 +22,24 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "github.com/apache/apisix-ingress-controller/pkg/ingress/namespace"
"github.com/apache/apisix-ingress-controller/pkg/metrics"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
+ providertypes "github.com/apache/apisix-ingress-controller/pkg/providers/types"
"github.com/apache/apisix-ingress-controller/pkg/types"
)
-func TestPodOnAdd(t *testing.T) {
- ctl := &podController{
- controller: &Controller{
- namespaceProvider: namespace.NewMockWatchingProvider([]string{"default"}),
- podCache: types.NewPodCache(),
- MetricsCollector: metrics.NewPrometheusCollector(),
+func mockController() *podController {
+ return &podController{
+ podCache: types.NewPodCache(),
+ namespaceProvider: namespace.NewMockWatchingNamespaceProvider([]string{"default"}),
+ Common: &providertypes.Common{
+ MetricsCollector: metrics.NewPrometheusCollector(),
},
}
+}
+
+func TestPodOnAdd(t *testing.T) {
+ ctl := mockController()
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -47,7 +52,7 @@ func TestPodOnAdd(t *testing.T) {
},
}
ctl.onAdd(pod)
- name, err := ctl.controller.podCache.GetNameByIP("10.0.5.12")
+ name, err := ctl.podCache.GetNameByIP("10.0.5.12")
assert.Nil(t, err)
assert.Equal(t, "nginx", name)
@@ -62,19 +67,13 @@ func TestPodOnAdd(t *testing.T) {
},
}
ctl.onAdd(pod2)
- name, err = ctl.controller.podCache.GetNameByIP("10.0.5.13")
+ name, err = ctl.podCache.GetNameByIP("10.0.5.13")
assert.Empty(t, name)
assert.Equal(t, types.ErrPodNotFound, err)
}
func TestPodOnDelete(t *testing.T) {
- ctl := &podController{
- controller: &Controller{
- namespaceProvider: namespace.NewMockWatchingProvider([]string{"default"}),
- podCache: types.NewPodCache(),
- MetricsCollector: metrics.NewPrometheusCollector(),
- },
- }
+ ctl := mockController()
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -86,10 +85,10 @@ func TestPodOnDelete(t *testing.T) {
PodIP: "10.0.5.12",
},
}
- assert.Nil(t, ctl.controller.podCache.Add(pod), "adding pod")
+ assert.Nil(t, ctl.podCache.Add(pod), "adding pod")
ctl.onDelete(pod)
- name, err := ctl.controller.podCache.GetNameByIP("10.0.5.12")
+ name, err := ctl.podCache.GetNameByIP("10.0.5.12")
assert.Empty(t, name)
assert.Equal(t, types.ErrPodNotFound, err)
@@ -103,21 +102,15 @@ func TestPodOnDelete(t *testing.T) {
PodIP: "10.0.5.13",
},
}
- assert.Nil(t, ctl.controller.podCache.Add(pod2), "adding pod")
+ assert.Nil(t, ctl.podCache.Add(pod2), "adding pod")
ctl.onDelete(pod2)
- name, err = ctl.controller.podCache.GetNameByIP("10.0.5.13")
+ name, err = ctl.podCache.GetNameByIP("10.0.5.13")
assert.Equal(t, "abc", name)
assert.Nil(t, err)
}
func TestPodOnUpdate(t *testing.T) {
- ctl := &podController{
- controller: &Controller{
- namespaceProvider: namespace.NewMockWatchingProvider([]string{"default"}),
- podCache: types.NewPodCache(),
- MetricsCollector: metrics.NewPrometheusCollector(),
- },
- }
+ ctl := mockController()
pod0 := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -136,12 +129,12 @@ func TestPodOnUpdate(t *testing.T) {
pod1.SetResourceVersion("1")
ctl.onUpdate(pod1, pod0)
- name, err := ctl.controller.podCache.GetNameByIP("10.0.5.12")
+ name, err := ctl.podCache.GetNameByIP("10.0.5.12")
assert.Equal(t, "", name)
assert.Equal(t, types.ErrPodNotFound, err)
ctl.onUpdate(pod0, pod1)
- name, err = ctl.controller.podCache.GetNameByIP("10.0.5.12")
+ name, err = ctl.podCache.GetNameByIP("10.0.5.12")
assert.Equal(t, "nginx", name)
assert.Equal(t, nil, err)
@@ -156,9 +149,9 @@ func TestPodOnUpdate(t *testing.T) {
PodIP: "10.0.5.13",
},
}
- assert.Nil(t, ctl.controller.podCache.Add(pod2), "adding pod")
+ assert.Nil(t, ctl.podCache.Add(pod2), "adding pod")
ctl.onUpdate(pod1, pod2)
- name, err = ctl.controller.podCache.GetNameByIP("10.0.5.13")
+ name, err = ctl.podCache.GetNameByIP("10.0.5.13")
assert.Equal(t, "abc", name)
assert.Nil(t, err)
}
diff --git a/pkg/providers/k8s/pod/provider.go b/pkg/providers/k8s/pod/provider.go
new file mode 100644
index 00000000..50ceef5c
... 2930 lines suppressed ...