Skip to content

Commit 60e2ab6

Browse files
committed
feat: do not watch gateway api when disable
Signed-off-by: Ashing Zheng <[email protected]>
1 parent b83fd8e commit 60e2ab6

File tree

2 files changed

+200
-74
lines changed

2 files changed

+200
-74
lines changed

internal/manager/controllers.go

Lines changed: 112 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/apache/apisix-ingress-controller/internal/manager/readiness"
3838
"github.com/apache/apisix-ingress-controller/internal/provider"
3939
types "github.com/apache/apisix-ingress-controller/internal/types"
40+
"github.com/apache/apisix-ingress-controller/pkg/utils"
4041
)
4142

4243
// K8s
@@ -97,101 +98,138 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro
9798
if err := indexer.SetupIndexer(mgr); err != nil {
9899
return nil, err
99100
}
100-
return []Controller{
101-
&controller.GatewayClassReconciler{
101+
102+
setupLog := ctrl.LoggerFrom(ctx).WithName("setup")
103+
var controllers []Controller
104+
105+
// Gateway API Controllers - conditional registration based on API availability
106+
if utils.HasAPIResource(mgr, &gatewayv1.GatewayClass{}) {
107+
controllers = append(controllers, &controller.GatewayClassReconciler{
102108
Client: mgr.GetClient(),
103109
Scheme: mgr.GetScheme(),
104110
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("GatewayClass"),
105111
Updater: updater,
106-
},
107-
&controller.GatewayReconciler{
112+
})
113+
} else {
114+
setupLog.Info("Skipping GatewayClass controller setup, API not found in cluster", "api", "gateway.networking.k8s.io/v1.GatewayClass")
115+
}
116+
117+
if utils.HasAPIResource(mgr, &gatewayv1.Gateway{}) {
118+
controllers = append(controllers, &controller.GatewayReconciler{
108119
Client: mgr.GetClient(),
109120
Scheme: mgr.GetScheme(),
110121
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("Gateway"),
111122
Provider: pro,
112123
Updater: updater,
113-
},
114-
&controller.HTTPRouteReconciler{
124+
})
125+
} else {
126+
setupLog.Info("Skipping Gateway controller setup, API not found in cluster", "api", "gateway.networking.k8s.io/v1.Gateway")
127+
}
128+
129+
if utils.HasAPIResource(mgr, &gatewayv1.HTTPRoute{}) {
130+
controllers = append(controllers, &controller.HTTPRouteReconciler{
115131
Client: mgr.GetClient(),
116132
Scheme: mgr.GetScheme(),
117133
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("HTTPRoute"),
118134
Provider: pro,
119135
Updater: updater,
120136
Readier: readier,
121-
},
122-
&controller.IngressReconciler{
123-
Client: mgr.GetClient(),
124-
Scheme: mgr.GetScheme(),
125-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("Ingress"),
126-
Provider: pro,
127-
Updater: updater,
128-
Readier: readier,
129-
},
130-
&controller.ConsumerReconciler{
137+
})
138+
} else {
139+
setupLog.Info("Skipping HTTPRoute controller setup, API not found in cluster", "api", "gateway.networking.k8s.io/v1.HTTPRoute")
140+
}
141+
142+
// Core Kubernetes Controllers - always register these
143+
controllers = append(controllers, &controller.IngressReconciler{
144+
Client: mgr.GetClient(),
145+
Scheme: mgr.GetScheme(),
146+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("Ingress"),
147+
Provider: pro,
148+
Updater: updater,
149+
Readier: readier,
150+
})
151+
152+
controllers = append(controllers, &controller.IngressClassReconciler{
153+
Client: mgr.GetClient(),
154+
Scheme: mgr.GetScheme(),
155+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("IngressClass"),
156+
Provider: pro,
157+
})
158+
159+
// v1alpha1 Extension Controllers - conditional registration
160+
if utils.HasAPIResource(mgr, &v1alpha1.Consumer{}) {
161+
controllers = append(controllers, &controller.ConsumerReconciler{
131162
Client: mgr.GetClient(),
132163
Scheme: mgr.GetScheme(),
133164
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("Consumer"),
134165
Provider: pro,
135166
Updater: updater,
136167
Readier: readier,
137-
},
138-
&controller.IngressClassReconciler{
139-
Client: mgr.GetClient(),
140-
Scheme: mgr.GetScheme(),
141-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("IngressClass"),
142-
Provider: pro,
143-
},
144-
&controller.ApisixGlobalRuleReconciler{
145-
Client: mgr.GetClient(),
146-
Scheme: mgr.GetScheme(),
147-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixGlobalRule"),
148-
Provider: pro,
149-
Updater: updater,
150-
Readier: readier,
151-
},
152-
&controller.ApisixRouteReconciler{
153-
Client: mgr.GetClient(),
154-
Scheme: mgr.GetScheme(),
155-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixRoute"),
156-
Provider: pro,
157-
Updater: updater,
158-
Readier: readier,
159-
},
160-
&controller.ApisixConsumerReconciler{
161-
Client: mgr.GetClient(),
162-
Scheme: mgr.GetScheme(),
163-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixConsumer"),
164-
Provider: pro,
165-
Updater: updater,
166-
Readier: readier,
167-
},
168-
&controller.ApisixPluginConfigReconciler{
169-
Client: mgr.GetClient(),
170-
Scheme: mgr.GetScheme(),
171-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixPluginConfig"),
172-
Updater: updater,
173-
},
174-
&controller.ApisixTlsReconciler{
175-
Client: mgr.GetClient(),
176-
Scheme: mgr.GetScheme(),
177-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixTls"),
178-
Provider: pro,
179-
Updater: updater,
180-
Readier: readier,
181-
},
182-
&controller.ApisixUpstreamReconciler{
183-
Client: mgr.GetClient(),
184-
Scheme: mgr.GetScheme(),
185-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixUpstream"),
186-
Updater: updater,
187-
},
188-
&controller.GatewayProxyController{
189-
Client: mgr.GetClient(),
190-
Scheme: mgr.GetScheme(),
191-
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("GatewayProxy"),
192-
Provider: pro,
193-
},
194-
}, nil
168+
})
169+
} else {
170+
setupLog.Info("Skipping Consumer controller setup, API not found in cluster", "api", "apisix.apache.org/v1alpha1.Consumer")
171+
}
172+
173+
controllers = append(controllers, &controller.GatewayProxyController{
174+
Client: mgr.GetClient(),
175+
Scheme: mgr.GetScheme(),
176+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("GatewayProxy"),
177+
Provider: pro,
178+
})
179+
180+
// APISIX v2 Controllers - always register these as they are core to the controller
181+
controllers = append(controllers, &controller.ApisixGlobalRuleReconciler{
182+
Client: mgr.GetClient(),
183+
Scheme: mgr.GetScheme(),
184+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixGlobalRule"),
185+
Provider: pro,
186+
Updater: updater,
187+
Readier: readier,
188+
})
189+
190+
controllers = append(controllers, &controller.ApisixRouteReconciler{
191+
Client: mgr.GetClient(),
192+
Scheme: mgr.GetScheme(),
193+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixRoute"),
194+
Provider: pro,
195+
Updater: updater,
196+
Readier: readier,
197+
})
198+
199+
controllers = append(controllers, &controller.ApisixConsumerReconciler{
200+
Client: mgr.GetClient(),
201+
Scheme: mgr.GetScheme(),
202+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixConsumer"),
203+
Provider: pro,
204+
Updater: updater,
205+
Readier: readier,
206+
})
207+
208+
controllers = append(controllers, &controller.ApisixPluginConfigReconciler{
209+
Client: mgr.GetClient(),
210+
Scheme: mgr.GetScheme(),
211+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixPluginConfig"),
212+
Updater: updater,
213+
})
214+
215+
controllers = append(controllers, &controller.ApisixTlsReconciler{
216+
Client: mgr.GetClient(),
217+
Scheme: mgr.GetScheme(),
218+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixTls"),
219+
Provider: pro,
220+
Updater: updater,
221+
Readier: readier,
222+
})
223+
224+
controllers = append(controllers, &controller.ApisixUpstreamReconciler{
225+
Client: mgr.GetClient(),
226+
Scheme: mgr.GetScheme(),
227+
Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("ApisixUpstream"),
228+
Updater: updater,
229+
})
230+
231+
setupLog.Info("Controllers setup completed", "total_controllers", len(controllers))
232+
return controllers, nil
195233
}
196234

197235
func registerReadinessGVK(c client.Client, readier readiness.ReadinessManager) {

pkg/utils/cluster.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package utils
19+
20+
import (
21+
"github.com/go-logr/logr"
22+
"k8s.io/client-go/discovery"
23+
ctrl "sigs.k8s.io/controller-runtime"
24+
"sigs.k8s.io/controller-runtime/pkg/client"
25+
26+
"github.com/apache/apisix-ingress-controller/internal/types"
27+
)
28+
29+
// HasAPIResource checks if a specific API resource is available in the current cluster.
30+
// It uses the Discovery API to query the cluster's available resources and returns true
31+
// if the resource is found, false otherwise.
32+
//
33+
// This function gracefully handles errors and will return false if:
34+
// - The discovery client cannot be created
35+
// - The API server cannot be reached
36+
// - The group/version is not available
37+
// - Any other discovery-related error occurs
38+
//
39+
// Usage:
40+
//
41+
// if HasAPIResource(mgr, &gatewayv1.Gateway{}) {
42+
// // Gateway API is available, register the controller
43+
// } else {
44+
// // Gateway API not available, skip controller setup
45+
// }
46+
func HasAPIResource(mgr ctrl.Manager, obj client.Object) bool {
47+
return HasAPIResourceWithLogger(mgr, obj, ctrl.Log.WithName("api-detection"))
48+
}
49+
50+
// HasAPIResourceWithLogger is the same as HasAPIResource but accepts a custom logger
51+
// for more detailed debugging information.
52+
func HasAPIResourceWithLogger(mgr ctrl.Manager, obj client.Object, logger logr.Logger) bool {
53+
gvk := types.GvkOf(obj)
54+
groupVersion := gvk.GroupVersion().String()
55+
56+
logger = logger.WithValues(
57+
"kind", gvk.Kind,
58+
"group", gvk.Group,
59+
"version", gvk.Version,
60+
"groupVersion", groupVersion,
61+
)
62+
63+
// Create discovery client
64+
discoveryClient, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig())
65+
if err != nil {
66+
logger.Info("failed to create discovery client", "error", err)
67+
return false
68+
}
69+
70+
// Query server resources for the specific group/version
71+
apiResources, err := discoveryClient.ServerResourcesForGroupVersion(groupVersion)
72+
if err != nil {
73+
// This is expected for unsupported API versions, so we log at debug level
74+
logger.Info("group/version not available in cluster", "error", err)
75+
return false
76+
}
77+
78+
// Check if the specific kind exists in the resource list
79+
for _, res := range apiResources.APIResources {
80+
if res.Kind == gvk.Kind {
81+
logger.Info("API resource found in cluster")
82+
return true
83+
}
84+
}
85+
86+
logger.Info("API resource kind not found in group/version")
87+
return false
88+
}

0 commit comments

Comments
 (0)