This is an automated email from the ASF dual-hosted git repository.
alinsran 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 4f9cd000 feat: support disable gateway-api (#2672)
4f9cd000 is described below
commit 4f9cd000ce62b4db72b3746dd8a0f67aa4c17ded
Author: AlinsRan <[email protected]>
AuthorDate: Mon Dec 8 18:16:24 2025 +0800
feat: support disable gateway-api (#2672)
---
.github/workflows/apisix-e2e-test.yml | 64 ++++++
Makefile | 5 +-
config/samples/config.yaml | 2 +
internal/controller/config/types.go | 27 +--
internal/controller/consumer_controller.go | 5 +
internal/controller/gateway_controller.go | 31 +--
internal/controller/gatewayproxy_controller.go | 68 ++++---
internal/controller/indexer/indexer.go | 98 ++++++---
internal/manager/controllers.go | 268 ++++++++++++++++++-------
internal/manager/run.go | 2 +-
pkg/utils/k8s.go | 83 ++++++++
test/conformance/suite_test.go | 1 +
test/e2e/framework/apisix_consts.go | 3 +-
test/e2e/framework/ingress.go | 1 +
test/e2e/framework/manifests/ingress.yaml | 1 +
test/e2e/scaffold/apisix_deployer.go | 2 +
16 files changed, 500 insertions(+), 161 deletions(-)
diff --git a/.github/workflows/apisix-e2e-test.yml
b/.github/workflows/apisix-e2e-test.yml
index 45e0b070..c16bb625 100644
--- a/.github/workflows/apisix-e2e-test.yml
+++ b/.github/workflows/apisix-e2e-test.yml
@@ -116,3 +116,67 @@ jobs:
else
make ginkgo-e2e-test
fi
+
+ disable-gateway-api:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Setup Go Env
+ uses: actions/setup-go@v4
+ with:
+ go-version: "1.24"
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: "*"
+
+ - name: Install kind
+ run: |
+ go install sigs.k8s.io/[email protected]
+
+ - name: Install ginkgo
+ run: |
+ make install-ginkgo
+
+ - name: Build images
+ env:
+ TAG: dev
+ ARCH: amd64
+ ENABLE_PROXY: "false"
+ BASE_IMAGE_TAG: "debug"
+ run: |
+ echo "building images..."
+ make build-image
+
+ - name: Launch Kind Cluster
+ run: |
+ make kind-up
+
+ - name: Loading Docker Image to Kind Cluster
+ run: |
+ make kind-load-images
+
+ - name: Extract adc binary
+ if: ${{ env.ADC_VERSION == 'dev' }}
+ run: |
+ docker create --name adc-temp ghcr.io/api7/adc:dev
+ docker cp adc-temp:main.js adc.js
+ docker rm adc-temp
+ node $(pwd)/adc.js -v
+ echo "ADC_BIN=node $(pwd)/adc.js" >> $GITHUB_ENV
+
+ - name: Install CRDs
+ run: make install-crds
+
+ - name: Run E2E test suite
+ shell: bash
+ env:
+ TEST_DIR: "./test/e2e/apisix/"
+ TEST_ENV: CI
+ TEST_FOCUS: "Test ApisixRoute Basic tests"
+ run: make e2e-test
diff --git a/Makefile b/Makefile
index 39b1d6b0..69b94c71 100644
--- a/Makefile
+++ b/Makefile
@@ -290,7 +290,10 @@ uninstall-gateway-api: ## Uninstall Gateway API CRDs from
the K8s cluster specif
kubectl delete -f
https://github.com/kubernetes-sigs/gateway-api/releases/download/$(GATEAY_API_VERSION)/experimental-install.yaml
.PHONY: install
-install: manifests kustomize install-gateway-api ## Install CRDs into the K8s
cluster specified in ~/.kube/config.
+install: manifests kustomize install-gateway-api install-crds ## Install CRDs
and Gateway API into the K8s cluster specified in ~/.kube/config.
+
+.PHONY: install-crds
+install-crds: manifests kustomize ## Install CRDs into the K8s cluster
specified
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -
.PHONY: uninstall
diff --git a/config/samples/config.yaml b/config/samples/config.yaml
index 1959fe0a..8e371922 100644
--- a/config/samples/config.yaml
+++ b/config/samples/config.yaml
@@ -32,6 +32,8 @@ secure_metrics: false # The secure metrics
configuration.
exec_adc_timeout: 15s # The timeout for the ADC to execute.
# The default value is 15 seconds.
+disable_gateway_api: false # Whether to disable the Gateway API
support.
+ # The default value is false.
provider:
type: "apisix" # Provider type.
diff --git a/internal/controller/config/types.go
b/internal/controller/config/types.go
index 622beb16..e00ef1f4 100644
--- a/internal/controller/config/types.go
+++ b/internal/controller/config/types.go
@@ -55,19 +55,20 @@ const (
// Config contains all config items which are necessary for
// apisix-ingress-controller's running.
type Config struct {
- LogLevel string `json:"log_level" yaml:"log_level"`
- ControllerName string `json:"controller_name"
yaml:"controller_name"`
- LeaderElectionID string `json:"leader_election_id"
yaml:"leader_election_id"`
- MetricsAddr string `json:"metrics_addr"
yaml:"metrics_addr"`
- ServerAddr string `json:"server_addr"
yaml:"server_addr"`
- EnableServer bool `json:"enable_server"
yaml:"enable_server"`
- EnableHTTP2 bool `json:"enable_http2"
yaml:"enable_http2"`
- ProbeAddr string `json:"probe_addr"
yaml:"probe_addr"`
- SecureMetrics bool `json:"secure_metrics"
yaml:"secure_metrics"`
- LeaderElection *LeaderElection `json:"leader_election"
yaml:"leader_election"`
- ExecADCTimeout types.TimeDuration `json:"exec_adc_timeout"
yaml:"exec_adc_timeout"`
- ProviderConfig ProviderConfig `json:"provider" yaml:"provider"`
- Webhook *WebhookConfig `json:"webhook" yaml:"webhook"`
+ LogLevel string `json:"log_level" yaml:"log_level"`
+ ControllerName string `json:"controller_name"
yaml:"controller_name"`
+ LeaderElectionID string `json:"leader_election_id"
yaml:"leader_election_id"`
+ MetricsAddr string `json:"metrics_addr"
yaml:"metrics_addr"`
+ ServerAddr string `json:"server_addr"
yaml:"server_addr"`
+ EnableServer bool `json:"enable_server"
yaml:"enable_server"`
+ EnableHTTP2 bool `json:"enable_http2"
yaml:"enable_http2"`
+ ProbeAddr string `json:"probe_addr"
yaml:"probe_addr"`
+ SecureMetrics bool `json:"secure_metrics"
yaml:"secure_metrics"`
+ LeaderElection *LeaderElection `json:"leader_election"
yaml:"leader_election"`
+ ExecADCTimeout types.TimeDuration `json:"exec_adc_timeout"
yaml:"exec_adc_timeout"`
+ ProviderConfig ProviderConfig `json:"provider" yaml:"provider"`
+ Webhook *WebhookConfig `json:"webhook" yaml:"webhook"`
+ DisableGatewayAPI bool `json:"disable_gateway_api"
yaml:"disable_gateway_api"`
}
type GatewayConfig struct {
diff --git a/internal/controller/consumer_controller.go
b/internal/controller/consumer_controller.go
index 6ebe8c96..cfb1b296 100644
--- a/internal/controller/consumer_controller.go
+++ b/internal/controller/consumer_controller.go
@@ -44,6 +44,7 @@ import (
"github.com/apache/apisix-ingress-controller/internal/provider"
internaltypes
"github.com/apache/apisix-ingress-controller/internal/types"
"github.com/apache/apisix-ingress-controller/internal/utils"
+ pkgutils "github.com/apache/apisix-ingress-controller/pkg/utils"
)
// ConsumerReconciler reconciles a Gateway object.
@@ -60,6 +61,10 @@ type ConsumerReconciler struct { //nolint:revive
// SetupWithManager sets up the controller with the Manager.
func (r *ConsumerReconciler) SetupWithManager(mgr ctrl.Manager) error {
+ if config.ControllerConfig.DisableGatewayAPI ||
!pkgutils.HasAPIResource(mgr, &gatewayv1.Gateway{}) {
+ r.Log.Info("skipping Consumer controller setup as Gateway API
is not available")
+ return nil
+ }
return ctrl.NewControllerManagedBy(mgr).
For(&v1alpha1.Consumer{},
builder.WithPredicates(
diff --git a/internal/controller/gateway_controller.go
b/internal/controller/gateway_controller.go
index e2806304..db416817 100644
--- a/internal/controller/gateway_controller.go
+++ b/internal/controller/gateway_controller.go
@@ -43,6 +43,7 @@ import (
"github.com/apache/apisix-ingress-controller/internal/provider"
internaltypes
"github.com/apache/apisix-ingress-controller/internal/types"
"github.com/apache/apisix-ingress-controller/internal/utils"
+ pkgutils "github.com/apache/apisix-ingress-controller/pkg/utils"
)
// GatewayReconciler reconciles a Gateway object.
@@ -83,18 +84,6 @@ func (r *GatewayReconciler) SetupWithManager(mgr
ctrl.Manager) error {
&gatewayv1.GRPCRoute{},
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
).
- Watches(
- &gatewayv1alpha2.TCPRoute{},
-
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
- ).
- Watches(
- &gatewayv1alpha2.TLSRoute{},
-
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
- ).
- Watches(
- &gatewayv1alpha2.UDPRoute{},
-
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
- ).
Watches(
&v1alpha1.GatewayProxy{},
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForGatewayProxy),
@@ -110,6 +99,24 @@ func (r *GatewayReconciler) SetupWithManager(mgr
ctrl.Manager) error {
builder.WithPredicates(referenceGrantPredicates(KindGateway)),
)
}
+ if pkgutils.HasAPIResource(mgr, &gatewayv1alpha2.TCPRoute{}) {
+ bdr.Watches(
+ &gatewayv1alpha2.TCPRoute{},
+
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+ )
+ }
+ if pkgutils.HasAPIResource(mgr, &gatewayv1alpha2.TLSRoute{}) {
+ bdr.Watches(
+ &gatewayv1alpha2.TLSRoute{},
+
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+ )
+ }
+ if pkgutils.HasAPIResource(mgr, &gatewayv1alpha2.UDPRoute{}) {
+ bdr.Watches(
+ &gatewayv1alpha2.UDPRoute{},
+
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+ )
+ }
return bdr.Complete(r)
}
diff --git a/internal/controller/gatewayproxy_controller.go
b/internal/controller/gatewayproxy_controller.go
index b2dd7980..82bb2c71 100644
--- a/internal/controller/gatewayproxy_controller.go
+++ b/internal/controller/gatewayproxy_controller.go
@@ -39,6 +39,7 @@ import (
"github.com/apache/apisix-ingress-controller/internal/controller/indexer"
"github.com/apache/apisix-ingress-controller/internal/provider"
"github.com/apache/apisix-ingress-controller/internal/utils"
+ pkgutils "github.com/apache/apisix-ingress-controller/pkg/utils"
)
// GatewayProxyController reconciles a GatewayProxy object.
@@ -48,10 +49,15 @@ type GatewayProxyController struct {
Scheme *runtime.Scheme
Log logr.Logger
Provider provider.Provider
+
+ disableGatewayAPI bool
}
func (r *GatewayProxyController) SetupWithManager(mrg ctrl.Manager) error {
- return ctrl.NewControllerManagedBy(mrg).
+ if config.ControllerConfig.DisableGatewayAPI ||
!pkgutils.HasAPIResource(mrg, &gatewayv1.Gateway{}) {
+ r.disableGatewayAPI = true
+ }
+ builder := ctrl.NewControllerManagedBy(mrg).
For(&v1alpha1.GatewayProxy{}).
WithEventFilter(
predicate.Or(
@@ -68,13 +74,15 @@ func (r *GatewayProxyController) SetupWithManager(mrg
ctrl.Manager) error {
Watches(&corev1.Secret{},
handler.EnqueueRequestsFromMapFunc(r.listGatewayProxiesForSecret),
).
- Watches(&gatewayv1.Gateway{},
-
handler.EnqueueRequestsFromMapFunc(r.listGatewayProxiesByGateway),
- ).
Watches(&networkingv1.IngressClass{},
handler.EnqueueRequestsFromMapFunc(r.listGatewayProxiesForIngressClass),
- ).
- Complete(r)
+ )
+ if !r.disableGatewayAPI {
+ builder.Watches(&gatewayv1.Gateway{},
+
handler.EnqueueRequestsFromMapFunc(r.listGatewayProxiesByGateway),
+ )
+ }
+ return builder.Complete(r)
}
func (r *GatewayProxyController) Reconcile(ctx context.Context, req
ctrl.Request) (reconcile.Result, error) {
@@ -131,19 +139,32 @@ func (r *GatewayProxyController) Reconcile(ctx
context.Context, req ctrl.Request
ingressClassList networkingv1.IngressClassList
indexKey = indexer.GenIndexKey(gp.GetNamespace(),
gp.GetName())
)
- if err := r.List(ctx, &gatewayList,
client.MatchingFields{indexer.ParametersRef: indexKey}); err != nil {
- r.Log.Error(err, "failed to list GatewayList")
- return ctrl.Result{}, nil
- }
- var gatewayclassList gatewayv1.GatewayClassList
- if err := r.List(ctx, &gatewayclassList,
client.MatchingFields{indexer.ControllerName: config.GetControllerName()}); err
!= nil {
- r.Log.Error(err, "failed to list GatewayClassList")
- return ctrl.Result{}, nil
- }
- gcMatched := make(map[string]*gatewayv1.GatewayClass)
- for _, item := range gatewayclassList.Items {
- gcMatched[item.Name] = &item
+ if !r.disableGatewayAPI {
+ if err := r.List(ctx, &gatewayList,
client.MatchingFields{indexer.ParametersRef: indexKey}); err != nil {
+ r.Log.Error(err, "failed to list GatewayList")
+ return ctrl.Result{}, nil
+ }
+ var gatewayclassList gatewayv1.GatewayClassList
+ if err := r.List(ctx, &gatewayclassList,
client.MatchingFields{indexer.ControllerName: config.GetControllerName()}); err
!= nil {
+ r.Log.Error(err, "failed to list GatewayClassList")
+ return ctrl.Result{}, nil
+ }
+ gcMatched := make(map[string]*gatewayv1.GatewayClass)
+ for _, item := range gatewayclassList.Items {
+ gcMatched[item.Name] = &item
+ }
+ // append referrers to translate context
+ for _, item := range gatewayList.Items {
+ gcName := string(item.Spec.GatewayClassName)
+ if gcName == "" {
+ continue
+ }
+ if _, ok := gcMatched[gcName]; ok {
+ tctx.GatewayProxyReferrers[req.NamespacedName]
= append(tctx.GatewayProxyReferrers[req.NamespacedName],
utils.NamespacedNameKind(&item))
+ }
+ }
+ r.Log.V(1).Info("found Gateways for GatewayProxy",
"gatewayproxy", req.String(), "gateways", len(gatewayList.Items),
"gatewayclasses", len(gatewayclassList.Items), "ingressclasses",
len(ingressClassList.Items))
}
// list IngressClasses that reference the GatewayProxy
@@ -152,23 +173,12 @@ func (r *GatewayProxyController) Reconcile(ctx
context.Context, req ctrl.Request
return reconcile.Result{}, err
}
- // append referrers to translate context
- for _, item := range gatewayList.Items {
- gcName := string(item.Spec.GatewayClassName)
- if gcName == "" {
- continue
- }
- if _, ok := gcMatched[gcName]; ok {
- tctx.GatewayProxyReferrers[req.NamespacedName] =
append(tctx.GatewayProxyReferrers[req.NamespacedName],
utils.NamespacedNameKind(&item))
- }
- }
for _, item := range ingressClassList.Items {
if item.Spec.Controller != config.GetControllerName() {
continue
}
tctx.GatewayProxyReferrers[req.NamespacedName] =
append(tctx.GatewayProxyReferrers[req.NamespacedName],
utils.NamespacedNameKind(&item))
}
- r.Log.V(1).Info("found Gateways for GatewayProxy", "gatewayproxy",
req.String(), "gateways", len(gatewayList.Items), "gatewayclasses",
len(gatewayclassList.Items), "ingressclasses", len(ingressClassList.Items))
if len(tctx.GatewayProxyReferrers[req.NamespacedName]) == 0 {
return ctrl.Result{}, nil
diff --git a/internal/controller/indexer/indexer.go
b/internal/controller/indexer/indexer.go
index 223147ab..91bec714 100644
--- a/internal/controller/indexer/indexer.go
+++ b/internal/controller/indexer/indexer.go
@@ -34,6 +34,7 @@ import (
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations"
internaltypes
"github.com/apache/apisix-ingress-controller/internal/types"
+ "github.com/apache/apisix-ingress-controller/pkg/utils"
)
const (
@@ -54,29 +55,64 @@ const (
ControllerName = "controllerName"
)
-func SetupIndexer(mgr ctrl.Manager) error {
- for _, setup := range []func(ctrl.Manager) error{
- setupGatewayIndexer,
- setupHTTPRouteIndexer,
- setupTCPRouteIndexer,
- setupUDPRouteIndexer,
- setupGRPCRouteIndexer,
- setupTLSRouteIndexer,
- setupIngressIndexer,
- setupConsumerIndexer,
- setupBackendTrafficPolicyIndexer,
- setupIngressClassIndexer,
- setupGatewayProxyIndexer,
- setupGatewaySecretIndex,
- setupApisixRouteIndexer,
- setupApisixPluginConfigIndexer,
- setupApisixTlsIndexer,
- setupApisixConsumerIndexer,
- setupApisixGlobalRuleIndexer,
- setupGatewayClassIndexer,
+func SetupAPIv1alpha1Indexer(mgr ctrl.Manager) error {
+ setupLog :=
ctrl.LoggerFrom(context.Background()).WithName("indexer").WithName("apiv1alpha1")
+ for resource, setup := range map[client.Object]func(ctrl.Manager) error{
+ &v1alpha1.BackendTrafficPolicy{}:
setupBackendTrafficPolicyIndexer,
+ &v1alpha1.Consumer{}: setupConsumerIndexer,
+ &v1alpha1.GatewayProxy{}: setupGatewayProxyIndexer,
} {
- if err := setup(mgr); err != nil {
- return err
+ if utils.HasAPIResource(mgr, resource) {
+ if err := setup(mgr); err != nil {
+ return err
+ }
+ } else {
+ setupLog.Info("Skipping indexer setup, API not found in
cluster", "api", utils.FormatGVK(resource))
+ }
+ }
+ return nil
+}
+func SetupAPIv2Indexer(mgr ctrl.Manager) error {
+ setupLog :=
ctrl.LoggerFrom(context.Background()).WithName("indexer").WithName("apiv2")
+
+ for resource, setup := range map[client.Object]func(ctrl.Manager) error{
+ &networkingv1.IngressClass{}: setupIngressClassIndexer,
+ &networkingv1.Ingress{}: setupIngressIndexer,
+ &apiv2.ApisixConsumer{}: setupApisixConsumerIndexer,
+ &apiv2.ApisixRoute{}: setupApisixRouteIndexer,
+ &apiv2.ApisixPluginConfig{}: setupApisixPluginConfigIndexer,
+ &apiv2.ApisixTls{}: setupApisixTlsIndexer,
+ &apiv2.ApisixGlobalRule{}: setupApisixGlobalRuleIndexer,
+ } {
+ if utils.HasAPIResource(mgr, resource) {
+ if err := setup(mgr); err != nil {
+ return err
+ }
+ } else {
+ setupLog.Info("Skipping indexer setup, API not found in
cluster", "api", utils.FormatGVK(resource))
+ }
+ }
+ return nil
+}
+
+func SetupGatewayAPIIndexer(mgr ctrl.Manager) error {
+ setupLog :=
ctrl.LoggerFrom(context.Background()).WithName("indexer").WithName("gatewayapi")
+
+ for resource, setup := range map[client.Object]func(ctrl.Manager) error{
+ &gatewayv1.Gateway{}: setupGatewayIndexer,
+ &gatewayv1.HTTPRoute{}: setupHTTPRouteIndexer,
+ &gatewayv1.GRPCRoute{}: setupGRPCRouteIndexer,
+ &gatewayv1alpha2.TCPRoute{}: setupTCPRouteIndexer,
+ &gatewayv1alpha2.UDPRoute{}: setupUDPRouteIndexer,
+ &gatewayv1alpha2.TLSRoute{}: setupTLSRouteIndexer,
+ &gatewayv1.GatewayClass{}: setupGatewayClassIndexer,
+ } {
+ if utils.HasAPIResource(mgr, resource) {
+ if err := setup(mgr); err != nil {
+ return err
+ }
+ } else {
+ setupLog.Info("Skipping indexer setup, API not found in
cluster", "api", utils.FormatGVK(resource))
}
}
return nil
@@ -112,6 +148,15 @@ func setupGatewayIndexer(mgr ctrl.Manager) error {
return err
}
+ if err := mgr.GetFieldIndexer().IndexField(
+ context.Background(),
+ &gatewayv1.Gateway{},
+ SecretIndexRef,
+ GatewaySecretIndexFunc,
+ ); err != nil {
+ return err
+ }
+
return nil
}
@@ -334,15 +379,6 @@ func setupGatewayProxyIndexer(mgr ctrl.Manager) error {
return nil
}
-func setupGatewaySecretIndex(mgr ctrl.Manager) error {
- return mgr.GetFieldIndexer().IndexField(
- context.Background(),
- &gatewayv1.Gateway{},
- SecretIndexRef,
- GatewaySecretIndexFunc,
- )
-}
-
func setupGatewayClassIndexer(mgr ctrl.Manager) error {
return mgr.GetFieldIndexer().IndexField(
context.Background(),
diff --git a/internal/manager/controllers.go b/internal/manager/controllers.go
index 9c5b7290..38d437ac 100644
--- a/internal/manager/controllers.go
+++ b/internal/manager/controllers.go
@@ -33,11 +33,14 @@ import (
"github.com/apache/apisix-ingress-controller/api/v1alpha1"
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
"github.com/apache/apisix-ingress-controller/internal/controller"
+ "github.com/apache/apisix-ingress-controller/internal/controller/config"
"github.com/apache/apisix-ingress-controller/internal/controller/indexer"
"github.com/apache/apisix-ingress-controller/internal/controller/status"
"github.com/apache/apisix-ingress-controller/internal/manager/readiness"
"github.com/apache/apisix-ingress-controller/internal/provider"
types "github.com/apache/apisix-ingress-controller/internal/types"
+ "github.com/apache/apisix-ingress-controller/pkg/utils"
+ "github.com/go-logr/logr"
)
// K8s
@@ -103,24 +106,60 @@ type Controller interface {
}
func setupControllers(ctx context.Context, mgr manager.Manager, pro
provider.Provider, updater status.Updater, readier readiness.ReadinessManager)
([]Controller, error) {
- if err := indexer.SetupIndexer(mgr); err != nil {
+ setupLog := ctrl.LoggerFrom(ctx).WithName("setup")
+
+ if err := indexer.SetupAPIv1alpha1Indexer(mgr); err != nil {
+ setupLog.Error(err, "failed to setup v1alpha1 indexer")
+ return nil, err
+ }
+
+ runnables := []Controller{}
+ if controllers, err := setupGatewayAPIControllers(ctx, mgr, pro,
updater, readier); err != nil {
+ setupLog.Error(err, "failed to setup Gateway API controllers")
+ return nil, err
+ } else {
+ runnables = append(runnables, controllers...)
+ }
+
+ if controllers, err := setupAPIv2Controllers(ctx, mgr, pro, updater,
readier); err != nil {
+ setupLog.Error(err, "failed to setup API v2 controllers")
+ return nil, err
+ } else {
+ runnables = append(runnables, controllers...)
+ }
+
+ // required controller
+ runnables = append(runnables, &controller.GatewayProxyController{
+ Client: mgr.GetClient(),
+ Scheme: mgr.GetScheme(),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGatewayProxy),
+ Provider: pro,
+ })
+ return runnables, nil
+}
+
+func setupGatewayAPIControllers(ctx context.Context, mgr manager.Manager, pro
provider.Provider, updater status.Updater, readier readiness.ReadinessManager)
([]Controller, error) {
+ if err := indexer.SetupGatewayAPIIndexer(mgr); err != nil {
return nil, err
}
- return []Controller{
- &controller.GatewayClassReconciler{
+
+ setupLog :=
ctrl.LoggerFrom(ctx).WithName("setup").WithName("gatewayapi")
+ runnables := []Controller{}
+ for resource, controller := range map[client.Object]Controller{
+ &gatewayv1.GatewayClass{}: &controller.GatewayClassReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGatewayClass),
Updater: updater,
},
- &controller.GatewayReconciler{
+ &gatewayv1.Gateway{}: &controller.GatewayReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGateway),
Provider: pro,
Updater: updater,
},
- &controller.HTTPRouteReconciler{
+ &gatewayv1.HTTPRoute{}: &controller.HTTPRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindHTTPRoute),
@@ -128,31 +167,31 @@ func setupControllers(ctx context.Context, mgr
manager.Manager, pro provider.Pro
Updater: updater,
Readier: readier,
},
- &controller.TCPRouteReconciler{
+ &gatewayv1.GRPCRoute{}: &controller.GRPCRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindTCPRoute),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGRPCRoute),
Provider: pro,
Updater: updater,
Readier: readier,
},
- &controller.UDPRouteReconciler{
+ &gatewayv1alpha2.TCPRoute{}: &controller.TCPRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindUDPRoute),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindTCPRoute),
Provider: pro,
Updater: updater,
Readier: readier,
},
- &controller.GRPCRouteReconciler{
+ &gatewayv1alpha2.UDPRoute{}: &controller.UDPRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGRPCRoute),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindUDPRoute),
Provider: pro,
Updater: updater,
Readier: readier,
},
- &controller.TLSRouteReconciler{
+ &gatewayv1alpha2.TLSRoute{}: &controller.TLSRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindTLSRoute),
@@ -160,29 +199,48 @@ func setupControllers(ctx context.Context, mgr
manager.Manager, pro provider.Pro
Updater: updater,
Readier: readier,
},
- &controller.IngressReconciler{
+ &v1alpha1.Consumer{}: &controller.ConsumerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindIngress),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindConsumer),
Provider: pro,
Updater: updater,
Readier: readier,
},
- &controller.ConsumerReconciler{
+ } {
+ if utils.HasAPIResource(mgr, resource) {
+ runnables = append(runnables, controller)
+ } else {
+ setupLog.Info("Skipping indexer setup, API not found in
cluster", "api", utils.FormatGVK(resource))
+ }
+ }
+ return runnables, nil
+}
+
+func setupAPIv2Controllers(ctx context.Context, mgr manager.Manager, pro
provider.Provider, updater status.Updater, readier readiness.ReadinessManager)
([]Controller, error) {
+ if err := indexer.SetupAPIv2Indexer(mgr); err != nil {
+ return nil, err
+ }
+
+ setupLog := ctrl.LoggerFrom(ctx).WithName("setup").WithName("apiv2")
+
+ runnables := []Controller{}
+ for resource, controller := range map[client.Object]Controller{
+ &netv1.IngressClass{}: &controller.IngressClassReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindConsumer),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindIngressClass),
Provider: pro,
- Updater: updater,
- Readier: readier,
},
- &controller.IngressClassReconciler{
+ &netv1.Ingress{}: &controller.IngressReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindIngressClass),
+ Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindIngress),
Provider: pro,
+ Updater: updater,
+ Readier: readier,
},
- &controller.ApisixGlobalRuleReconciler{
+ &apiv2.ApisixGlobalRule{}:
&controller.ApisixGlobalRuleReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindApisixGlobalRule),
@@ -190,7 +248,7 @@ func setupControllers(ctx context.Context, mgr
manager.Manager, pro provider.Pro
Updater: updater,
Readier: readier,
},
- &controller.ApisixRouteReconciler{
+ &apiv2.ApisixRoute{}: &controller.ApisixRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindApisixRoute),
@@ -198,7 +256,7 @@ func setupControllers(ctx context.Context, mgr
manager.Manager, pro provider.Pro
Updater: updater,
Readier: readier,
},
- &controller.ApisixConsumerReconciler{
+ &apiv2.ApisixConsumer{}: &controller.ApisixConsumerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindApisixConsumer),
@@ -206,13 +264,13 @@ func setupControllers(ctx context.Context, mgr
manager.Manager, pro provider.Pro
Updater: updater,
Readier: readier,
},
- &controller.ApisixPluginConfigReconciler{
+ &apiv2.ApisixPluginConfig{}:
&controller.ApisixPluginConfigReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindApisixPluginConfig),
Updater: updater,
},
- &controller.ApisixTlsReconciler{
+ &apiv2.ApisixTls{}: &controller.ApisixTlsReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindApisixTls),
@@ -220,60 +278,124 @@ func setupControllers(ctx context.Context, mgr
manager.Manager, pro provider.Pro
Updater: updater,
Readier: readier,
},
- &controller.ApisixUpstreamReconciler{
+ &apiv2.ApisixUpstream{}: &controller.ApisixUpstreamReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindApisixUpstream),
Updater: updater,
},
- &controller.GatewayProxyController{
- Client: mgr.GetClient(),
- Scheme: mgr.GetScheme(),
- Log:
ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGatewayProxy),
- Provider: pro,
- },
- }, nil
+ } {
+ if utils.HasAPIResource(mgr, resource) {
+ runnables = append(runnables, controller)
+ } else {
+ setupLog.Info("Skipping indexer setup, API not found in
cluster", "api", utils.FormatGVK(resource))
+ }
+ }
+ return runnables, nil
}
-func registerReadinessGVK(c client.Client, readier readiness.ReadinessManager)
{
+func registerReadiness(mgr manager.Manager, readier
readiness.ReadinessManager) {
log := ctrl.LoggerFrom(context.Background()).WithName("readiness")
- readier.RegisterGVK([]readiness.GVKConfig{
- {
- GVKs: []schema.GroupVersionKind{
- types.GvkOf(&gatewayv1.HTTPRoute{}),
- types.GvkOf(&gatewayv1alpha2.TCPRoute{}),
- types.GvkOf(&gatewayv1alpha2.UDPRoute{}),
- types.GvkOf(&gatewayv1.GRPCRoute{}),
- types.GvkOf(&gatewayv1alpha2.TLSRoute{}),
- },
- },
- {
- GVKs: []schema.GroupVersionKind{
- types.GvkOf(&netv1.Ingress{}),
- types.GvkOf(&apiv2.ApisixRoute{}),
- types.GvkOf(&apiv2.ApisixGlobalRule{}),
- types.GvkOf(&apiv2.ApisixPluginConfig{}),
- types.GvkOf(&apiv2.ApisixTls{}),
- types.GvkOf(&apiv2.ApisixConsumer{}),
- types.GvkOf(&apiv2.ApisixUpstream{}),
- },
- Filter: readiness.GVKFilter(func(obj
*unstructured.Unstructured) bool {
- icName, _, _ :=
unstructured.NestedString(obj.Object, "spec", "ingressClassName")
- ingressClass, _ :=
controller.FindMatchingIngressClassByName(context.Background(), c, log, icName)
- return ingressClass != nil
- }),
- },
- {
- GVKs: []schema.GroupVersionKind{
- types.GvkOf(&v1alpha1.Consumer{}),
- },
- Filter: readiness.GVKFilter(func(obj
*unstructured.Unstructured) bool {
- consumer := &v1alpha1.Consumer{}
- if err :=
runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, consumer);
err != nil {
- return false
- }
- return
controller.MatchConsumerGatewayRef(context.Background(), c, log, consumer)
- }),
- },
- }...)
+
+ registerAPIv2ForReadiness(mgr, log, readier)
+ if !config.ControllerConfig.DisableGatewayAPI {
+ registerGatewayAPIForReadiness(mgr, log, readier)
+ }
+ registerAPIv1alpha1ForReadiness(mgr, log, readier)
+}
+
+func registerGatewayAPIForReadiness(
+ mgr manager.Manager,
+ log logr.Logger,
+ readier readiness.ReadinessManager,
+) {
+ var installed []schema.GroupVersionKind
+ for _, resource := range []client.Object{
+ &gatewayv1.HTTPRoute{},
+ &gatewayv1.GRPCRoute{},
+ &gatewayv1alpha2.TCPRoute{},
+ &gatewayv1alpha2.UDPRoute{},
+ &gatewayv1alpha2.TLSRoute{},
+ } {
+ gvk := types.GvkOf(resource)
+ if utils.HasAPIResource(mgr, resource) {
+ installed = append(installed, gvk)
+ } else {
+ log.Info("Skipping readiness registration, API not
found", "gvk", gvk)
+ }
+ }
+ if len(installed) == 0 {
+ return
+ }
+
+ readier.RegisterGVK(readiness.GVKConfig{GVKs: installed})
+}
+
+func registerAPIv2ForReadiness(
+ mgr manager.Manager,
+ log logr.Logger,
+ readier readiness.ReadinessManager,
+) {
+ var installed []schema.GroupVersionKind
+ for _, resource := range []client.Object{
+ &netv1.Ingress{},
+ &apiv2.ApisixRoute{},
+ &apiv2.ApisixGlobalRule{},
+ &apiv2.ApisixPluginConfig{},
+ &apiv2.ApisixTls{},
+ &apiv2.ApisixConsumer{},
+ &apiv2.ApisixUpstream{},
+ } {
+ gvk := types.GvkOf(resource)
+ if utils.HasAPIResource(mgr, resource) {
+ installed = append(installed, gvk)
+ } else {
+ log.Info("Skipping readiness registration, API not
found", "gvk", gvk)
+ }
+ }
+
+ if len(installed) == 0 {
+ return
+ }
+
+ readier.RegisterGVK(readiness.GVKConfig{
+ GVKs: installed,
+ Filter: readiness.GVKFilter(func(obj
*unstructured.Unstructured) bool {
+ icName, _, _ := unstructured.NestedString(obj.Object,
"spec", "ingressClassName")
+ ingressClass, _ :=
controller.FindMatchingIngressClassByName(context.Background(),
mgr.GetClient(), log, icName)
+ return ingressClass != nil
+ }),
+ })
+}
+
+func registerAPIv1alpha1ForReadiness(
+ mgr manager.Manager,
+ log logr.Logger,
+ readier readiness.ReadinessManager,
+) {
+ var installed []schema.GroupVersionKind
+ for _, resource := range []client.Object{
+ &v1alpha1.Consumer{},
+ } {
+ gvk := types.GvkOf(resource)
+ if utils.HasAPIResource(mgr, resource) {
+ installed = append(installed, gvk)
+ } else {
+ log.Info("Skipping readiness registration, API not
found", "gvk", gvk)
+ }
+ }
+ if len(installed) == 0 {
+ return
+ }
+
+ readier.RegisterGVK(readiness.GVKConfig{
+ GVKs: installed,
+ Filter: readiness.GVKFilter(func(obj
*unstructured.Unstructured) bool {
+ consumer := &v1alpha1.Consumer{}
+ if err :=
runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, consumer);
err != nil {
+ return false
+ }
+ return
controller.MatchConsumerGatewayRef(context.Background(), mgr.GetClient(), log,
consumer)
+ }),
+ })
}
diff --git a/internal/manager/run.go b/internal/manager/run.go
index d8f07cf5..28a840bb 100644
--- a/internal/manager/run.go
+++ b/internal/manager/run.go
@@ -165,7 +165,7 @@ func Run(ctx context.Context, logger logr.Logger) error {
}
readier := readiness.NewReadinessManager(mgr.GetClient(), logger)
- registerReadinessGVK(mgr.GetClient(), readier)
+ registerReadiness(mgr, readier)
if err := mgr.Add(readier); err != nil {
setupLog.Error(err, "unable to add readiness manager")
diff --git a/pkg/utils/k8s.go b/pkg/utils/k8s.go
new file mode 100644
index 00000000..425f2ff9
--- /dev/null
+++ b/pkg/utils/k8s.go
@@ -0,0 +1,83 @@
+// 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 utils
+
+import (
+ "github.com/go-logr/logr"
+ "k8s.io/client-go/discovery"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+
+ "github.com/apache/apisix-ingress-controller/internal/types"
+)
+
+// HasAPIResource checks if a specific API resource is available in the
current cluster.
+// It uses the Discovery API to query the cluster's available resources and
returns true
+// if the resource is found, false otherwise.
+func HasAPIResource(mgr ctrl.Manager, obj client.Object) bool {
+ return HasAPIResourceWithLogger(mgr, obj,
ctrl.Log.WithName("api-detection"))
+}
+
+// HasAPIResourceWithLogger is the same as HasAPIResource but accepts a custom
logger
+// for more detailed debugging information.
+func HasAPIResourceWithLogger(mgr ctrl.Manager, obj client.Object, logger
logr.Logger) bool {
+ gvk, err := apiutil.GVKForObject(obj, mgr.GetScheme())
+ if err != nil {
+ logger.Info("cannot derive GVK from scheme", "error", err)
+ return false
+ }
+
+ groupVersion := gvk.GroupVersion().String()
+
+ logger = logger.WithValues(
+ "kind", gvk.Kind,
+ "group", gvk.Group,
+ "version", gvk.Version,
+ "groupVersion", groupVersion,
+ )
+
+ // Create discovery client
+ discoveryClient, err :=
discovery.NewDiscoveryClientForConfig(mgr.GetConfig())
+ if err != nil {
+ logger.Info("failed to create discovery client", "error", err)
+ return false
+ }
+
+ // Query server resources for the specific group/version
+ apiResources, err :=
discoveryClient.ServerResourcesForGroupVersion(groupVersion)
+ if err != nil {
+ logger.Info("group/version not available in cluster", "error",
err)
+ return false
+ }
+
+ // Check if the specific kind exists in the resource list
+ for _, res := range apiResources.APIResources {
+ if res.Kind == gvk.Kind {
+ return true
+ }
+ }
+
+ logger.Info("API resource kind not found in group/version")
+ return false
+}
+
+func FormatGVK(obj client.Object) string {
+ gvk := types.GvkOf(obj)
+ return gvk.String()
+}
diff --git a/test/conformance/suite_test.go b/test/conformance/suite_test.go
index e7ab91b1..0ae3bc70 100644
--- a/test/conformance/suite_test.go
+++ b/test/conformance/suite_test.go
@@ -170,6 +170,7 @@ func TestMain(m *testing.M) {
InitSyncDelay: 20 * time.Minute,
ProviderType: framework.ProviderType,
ProviderSyncPeriod: 1 * time.Hour,
+ DisableGatewayAPI: framework.DisableGatewayAPI,
})
adminEndpoint := fmt.Sprintf("http://%s.%s:9180", svc.Name, namespace)
diff --git a/test/e2e/framework/apisix_consts.go
b/test/e2e/framework/apisix_consts.go
index cbaa91b8..0d1d18c3 100644
--- a/test/e2e/framework/apisix_consts.go
+++ b/test/e2e/framework/apisix_consts.go
@@ -27,7 +27,8 @@ import (
)
var (
- ProviderType = cmp.Or(os.Getenv("PROVIDER_TYPE"), "apisix")
+ ProviderType = cmp.Or(os.Getenv("PROVIDER_TYPE"), "apisix")
+ DisableGatewayAPI = os.Getenv("DISABLE_GATEWAY_API") == "true"
)
const (
diff --git a/test/e2e/framework/ingress.go b/test/e2e/framework/ingress.go
index 9c2e7199..fe627be8 100644
--- a/test/e2e/framework/ingress.go
+++ b/test/e2e/framework/ingress.go
@@ -53,6 +53,7 @@ type IngressDeployOpts struct {
InitSyncDelay time.Duration
WebhookEnable bool
WebhookPort int
+ DisableGatewayAPI bool
}
func (f *Framework) DeployIngress(opts IngressDeployOpts) {
diff --git a/test/e2e/framework/manifests/ingress.yaml
b/test/e2e/framework/manifests/ingress.yaml
index a9d50d65..2c240d7f 100644
--- a/test/e2e/framework/manifests/ingress.yaml
+++ b/test/e2e/framework/manifests/ingress.yaml
@@ -281,6 +281,7 @@ data:
log_level: "debug"
controller_name: {{ .ControllerName | default
"apisix.apache.org/apisix-ingress-controller" }}
leader_election_id: "apisix-ingress-controller-leader"
+ disable_gateway_api: {{ .DisableGatewayAPI | default false }}
leader_election:
lease_duration: 10s # lease_duration is the duration
that non-leader candidates will wait
# after observing a leadership
renewal until attempting to acquire leadership of a
diff --git a/test/e2e/scaffold/apisix_deployer.go
b/test/e2e/scaffold/apisix_deployer.go
index 51d16d27..58f6a79c 100644
--- a/test/e2e/scaffold/apisix_deployer.go
+++ b/test/e2e/scaffold/apisix_deployer.go
@@ -270,6 +270,7 @@ func (s *APISIXDeployer) DeployIngress() {
Namespace: s.namespace,
Replicas: ptr.To(1),
WebhookEnable: s.runtimeOpts.EnableWebhook,
+ DisableGatewayAPI: framework.DisableGatewayAPI,
})
}
@@ -280,6 +281,7 @@ func (s *APISIXDeployer) ScaleIngress(replicas int) {
ProviderSyncPeriod: 1 * time.Hour,
Namespace: s.namespace,
Replicas: ptr.To(replicas),
+ DisableGatewayAPI: framework.DisableGatewayAPI,
})
}