1515package k8s
1616
1717import (
18+ "context"
1819 "errors"
1920 "os"
2021 "path/filepath"
@@ -31,6 +32,9 @@ import (
3132 crinformers "github.com/haproxytech/kubernetes-ingress/crs/generated/informers/externalversions"
3233 "github.com/haproxytech/kubernetes-ingress/pkg/ingress"
3334 "github.com/haproxytech/kubernetes-ingress/pkg/utils"
35+ crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
36+ errGw "k8s.io/apimachinery/pkg/api/errors"
37+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3438 "sigs.k8s.io/controller-runtime/pkg/client"
3539 gatewayclientset "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
3640 scheme "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/scheme"
@@ -44,15 +48,17 @@ const (
4448 TRACE_API = false //nolint:golint,stylecheck
4549 CRSGroupVersionV1alpha1 = "core.haproxy.org/v1alpha1"
4650 CRSGroupVersionV1alpha2 = "core.haproxy.org/v1alpha2"
51+ GATEWAY_API_VERSION = "v0.5.1" //nolint:golint,stylecheck
4752)
4853
4954var ErrIgnored = errors .New ("ignored resource" )
5055
5156type K8s interface {
5257 GetRestClientset () client.Client
5358 GetClientset () * k8sclientset.Clientset
54- MonitorChanges (eventChan chan SyncDataEvent , stop chan struct {}, osArgs utils.OSArgs )
59+ MonitorChanges (eventChan chan SyncDataEvent , stop chan struct {}, osArgs utils.OSArgs , gatewayAPIInstalled bool )
5560 UpdatePublishService (ingresses []* ingress.Ingress , publishServiceAddresses []string )
61+ IsGatewayAPIInstalled (gatewayControllerName string ) bool
5662}
5763
5864// A Custom Resource interface
@@ -77,6 +83,8 @@ type k8s struct {
7783 syncPeriod time.Duration
7884 cacheResyncPeriod time.Duration
7985 disableSvcExternalName bool // CVE-2021-25740
86+ crdClient * crdclientset.Clientset
87+ gatewayAPIInstalled bool
8088}
8189
8290func New (osArgs utils.OSArgs , whitelist map [string ]struct {}, publishSvc * utils.NamespaceValue ) K8s { //nolint:ireturn
@@ -104,6 +112,11 @@ func New(osArgs utils.OSArgs, whitelist map[string]struct{}, publishSvc *utils.N
104112 logger .Print ("Gateway API not present" )
105113 }
106114
115+ crdClient , err := crdclientset .NewForConfig (restconfig )
116+ if err != nil {
117+ logger .Error ("CRD API client not present" )
118+ }
119+
107120 prefix , _ := utils .GetPodPrefix (os .Getenv ("POD_NAME" ))
108121 k := k8s {
109122 builtInClient : builtInClient ,
@@ -118,6 +131,7 @@ func New(osArgs utils.OSArgs, whitelist map[string]struct{}, publishSvc *utils.N
118131 disableSvcExternalName : osArgs .DisableServiceExternalName ,
119132 gatewayClient : gatewayClient ,
120133 gatewayRestClient : gatewayRestClient ,
134+ crdClient : crdClient ,
121135 }
122136 // alpha1 is deprecated
123137 k .registerCoreCR (NewGlobalCRV1Alpha1 (), CRSGroupVersionV1alpha1 )
@@ -145,14 +159,13 @@ func (k k8s) UpdatePublishService(ingresses []*ingress.Ingress, publishServiceAd
145159 }
146160}
147161
148- func (k k8s ) MonitorChanges (eventChan chan SyncDataEvent , stop chan struct {}, osArgs utils.OSArgs ) {
162+ func (k k8s ) MonitorChanges (eventChan chan SyncDataEvent , stop chan struct {}, osArgs utils.OSArgs , gatewayAPIInstalled bool ) {
149163 informersSynced := & []cache.InformerSynced {}
150- needGatewayAPIInformers := k .isGatewayAPIInstalled () && osArgs .GatewayControllerName != ""
151164 k .runPodInformer (eventChan , stop , informersSynced )
152165 for _ , namespace := range k .whiteListedNS {
153166 k .runInformers (eventChan , stop , namespace , informersSynced )
154167 k .runCRInformers (eventChan , stop , namespace , informersSynced )
155- if needGatewayAPIInformers {
168+ if gatewayAPIInstalled {
156169 k .runInformersGwAPI (eventChan , stop , namespace , informersSynced )
157170 }
158171 }
@@ -320,7 +333,43 @@ func getWhitelistedNS(whitelist map[string]struct{}, cfgMapNS string) []string {
320333 return namespaces
321334}
322335
323- func (k k8s ) isGatewayAPIInstalled () bool {
324- _ , err := k .crClient .DiscoveryClient .ServerResourcesForGroupVersion ("gateway.networking.k8s.io/v1beta1" )
325- return err == nil
336+ func (k k8s ) IsGatewayAPIInstalled (gatewayControllerName string ) (installed bool ) {
337+ installed = true
338+ defer func () {
339+ k .gatewayAPIInstalled = installed
340+ }()
341+ gatewayCrd , err := k .crdClient .ApiextensionsV1 ().CustomResourceDefinitions ().Get (context .Background (), "gateways.gateway.networking.k8s.io" , metav1.GetOptions {})
342+ if err != nil {
343+ var errStatus * errGw.StatusError
344+ if ! errors .As (err , & errStatus ) || errStatus .ErrStatus .Code != 404 {
345+ logger .Error (err )
346+ return false
347+ }
348+ }
349+
350+ if gatewayCrd .Name == "" {
351+ if gatewayControllerName != "" {
352+ logger .Errorf ("No gateway api is installed, please install experimental yaml version %s" , GATEWAY_API_VERSION )
353+ }
354+ return false
355+ }
356+
357+ log := logger .Warningf
358+ if gatewayControllerName != "" {
359+ log = logger .Errorf
360+ }
361+
362+ version := gatewayCrd .Annotations ["gateway.networking.k8s.io/bundle-version" ]
363+ if version != GATEWAY_API_VERSION {
364+ log ("Unsupported version '%s' of gateway api is installed, please install experimental yaml version %s" , version , GATEWAY_API_VERSION )
365+ installed = false
366+ }
367+
368+ // gatewayCrd is not nil so gateway API is present
369+ tcprouteCrd , err := k .crdClient .ApiextensionsV1 ().CustomResourceDefinitions ().Get (context .Background (), "tcproutes.gateway.networking.k8s.io" , metav1.GetOptions {})
370+ if tcprouteCrd == nil || err != nil {
371+ log ("No tcproute crd is installed, please install experimental yaml version %s" , GATEWAY_API_VERSION )
372+ installed = false
373+ }
374+ return
326375}
0 commit comments