@@ -16,37 +16,69 @@ import (
16
16
"github.com/TykTechnologies/tyk-k8s/tyk"
17
17
"k8s.io/api/core/v1"
18
18
"k8s.io/api/extensions/v1beta1"
19
- v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
20
- "k8s.io/apimachinery/pkg/fields"
19
+ netv1beta1 "k8s.io/api/networking/v1beta1"
20
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21
+ "k8s.io/apimachinery/pkg/runtime"
22
+ "k8s.io/apimachinery/pkg/util/version"
23
+ "k8s.io/client-go/informers"
21
24
"k8s.io/client-go/kubernetes"
22
25
"k8s.io/client-go/rest"
23
26
"k8s.io/client-go/tools/cache"
24
27
"k8s.io/client-go/tools/clientcmd"
25
28
)
26
29
27
- type Config struct {}
30
+ type Config struct {
31
+ WatchNamespaces []string
32
+ }
28
33
29
34
var ctrl * ControlServer
30
35
var log = logger .GetLogger ("ingress" )
31
36
var opLog = sync.Map {}
37
+ var runtimeScheme = runtime .NewScheme ()
32
38
33
39
const (
34
40
IngressAnnotation = "kubernetes.io/ingress.class"
35
41
IngressAnnotationValue = "tyk"
42
+ defaultResync = 2 * time .Minute
36
43
)
37
44
38
45
type ControlServer struct {
39
- cfg * Config
40
- client * kubernetes.Clientset
41
- store cache.Store
42
- ingressController cache.Controller
43
- podController cache.Controller
44
- stopCh chan struct {}
46
+ cfg * Config
47
+ client * kubernetes.Clientset
48
+ stopCh chan struct {}
49
+ factories map [string ]informers.SharedInformerFactory
50
+ isNetworkingIngress bool
51
+ }
52
+
53
+ func init () {
54
+ v1beta1 .AddToScheme (runtimeScheme )
55
+ netv1beta1 .AddToScheme (runtimeScheme )
56
+ }
57
+
58
+ func convertIngress (obj interface {}) (* netv1beta1.Ingress , bool ) {
59
+ extIngress , ok := obj .(* v1beta1.Ingress )
60
+ if ok {
61
+ netIngress := & netv1beta1.Ingress {}
62
+ if err := runtimeScheme .Convert (extIngress , netIngress , nil ); err != nil {
63
+ log .Errorf ("error converting ingress from extensions/v1beta1: %v" , err )
64
+ return nil , false
65
+ }
66
+
67
+ return netIngress , true
68
+ }
69
+
70
+ if ing , ok := obj .(* netv1beta1.Ingress ); ok {
71
+ return ing , true
72
+ }
73
+
74
+ return nil , false
45
75
}
46
76
47
77
func NewController () * ControlServer {
48
78
if ctrl == nil {
49
- ctrl = & ControlServer {}
79
+ ctrl = & ControlServer {
80
+ factories : make (map [string ]informers.SharedInformerFactory ),
81
+ }
50
82
}
51
83
52
84
return ctrl
@@ -60,6 +92,11 @@ func Controller() *ControlServer {
60
92
return ctrl
61
93
}
62
94
95
+ func (c * ControlServer ) Config (cfg * Config ) * ControlServer {
96
+ c .cfg = cfg
97
+ return c
98
+ }
99
+
63
100
func (c * ControlServer ) getClient () (* kubernetes.Clientset , error ) {
64
101
cfgF := os .Getenv ("TYK_K8S_KUBECONF" )
65
102
var config * rest.Config
@@ -85,10 +122,9 @@ func (c *ControlServer) Start() error {
85
122
if err != nil {
86
123
return err
87
124
}
125
+ c .setNetworkingIngress ()
88
126
89
- c .watchIngresses ()
90
- c .watchPods ()
91
- return nil
127
+ return c .watchAll ()
92
128
}
93
129
94
130
func (c * ControlServer ) Stop () error {
@@ -110,7 +146,7 @@ func (c *ControlServer) getAPIName(name, service string) string {
110
146
return v
111
147
}
112
148
113
- func (c * ControlServer ) generateIngressID (ingressName , ns string , p v1beta1 .HTTPIngressPath ) string {
149
+ func (c * ControlServer ) generateIngressID (ingressName , ns string , p netv1beta1 .HTTPIngressPath ) string {
114
150
serviceFQDN := fmt .Sprintf ("%s.%s.%s/%s" , ingressName , ns , p .Backend .ServiceName , p .Path )
115
151
hasher := sha1 .New ()
116
152
hasher .Write ([]byte (serviceFQDN ))
@@ -119,12 +155,12 @@ func (c *ControlServer) generateIngressID(ingressName, ns string, p v1beta1.HTTP
119
155
return sha
120
156
}
121
157
122
- func (c * ControlServer ) handleTLS (ing * v1beta1 .Ingress ) (map [string ]string , error ) {
158
+ func (c * ControlServer ) handleTLS (ing * netv1beta1 .Ingress ) (map [string ]string , error ) {
123
159
log .Info ("checking for TLS entries" )
124
160
certMap := map [string ]string {}
125
161
for _ , iTLS := range ing .Spec .TLS {
126
162
log .Info ("found TLS entry: " , iTLS .String ())
127
- sec , err := c .client .CoreV1 ().Secrets (ing .Namespace ).Get (iTLS .SecretName , v12 .GetOptions {})
163
+ sec , err := c .client .CoreV1 ().Secrets (ing .Namespace ).Get (iTLS .SecretName , metav1 .GetOptions {})
128
164
if err != nil {
129
165
return nil , err
130
166
}
@@ -156,7 +192,7 @@ func (c *ControlServer) handleTLS(ing *v1beta1.Ingress) (map[string]string, erro
156
192
157
193
}
158
194
159
- func checkAndGetTemplate (ing * v1beta1 .Ingress ) string {
195
+ func checkAndGetTemplate (ing * netv1beta1 .Ingress ) string {
160
196
for k , v := range ing .Annotations {
161
197
if k == tyk .TemplateNameKey {
162
198
log .Infof ("template annotation found with value: %v" , v )
@@ -167,7 +203,7 @@ func checkAndGetTemplate(ing *v1beta1.Ingress) string {
167
203
return tyk .DefaultIngressTemplate
168
204
}
169
205
170
- func (c * ControlServer ) doAdd (ing * v1beta1 .Ingress ) error {
206
+ func (c * ControlServer ) doAdd (ing * netv1beta1 .Ingress ) error {
171
207
tags := []string {"ingress" }
172
208
hName := ""
173
209
@@ -227,7 +263,7 @@ func (c *ControlServer) doAdd(ing *v1beta1.Ingress) error {
227
263
}
228
264
229
265
func (c * ControlServer ) handleIngressAdd (obj interface {}) {
230
- ing , ok := obj .( * v1beta1. Ingress )
266
+ ing , ok := convertIngress ( obj )
231
267
if ! ok {
232
268
log .Errorf ("type not allowed: %v" , reflect .TypeOf (obj ))
233
269
return
@@ -244,7 +280,7 @@ func (c *ControlServer) handleIngressAdd(obj interface{}) {
244
280
}
245
281
246
282
func (c * ControlServer ) handleIngressUpdate (oldObj interface {}, newObj interface {}) {
247
- oldIng , ok := oldObj .( * v1beta1. Ingress )
283
+ oldIng , ok := convertIngress ( oldObj )
248
284
if ! ok {
249
285
log .Errorf ("type not allowed: %v" , reflect .TypeOf (oldIng ))
250
286
return
@@ -254,7 +290,7 @@ func (c *ControlServer) handleIngressUpdate(oldObj interface{}, newObj interface
254
290
return
255
291
}
256
292
257
- newIng , ok := newObj .( * v1beta1. Ingress )
293
+ newIng , ok := convertIngress ( newObj )
258
294
if ! ok {
259
295
log .Errorf ("type not allowed: %v" , reflect .TypeOf (newIng ))
260
296
return
@@ -300,7 +336,7 @@ func (c *ControlServer) handleIngressUpdate(oldObj interface{}, newObj interface
300
336
301
337
}
302
338
303
- func (c * ControlServer ) ingressChanged (old * v1beta1 .Ingress , new * v1beta1 .Ingress ) bool {
339
+ func (c * ControlServer ) ingressChanged (old * netv1beta1 .Ingress , new * netv1beta1 .Ingress ) bool {
304
340
if len (new .Spec .Rules ) > 0 {
305
341
r0 := new .Spec .Rules [0 ]
306
342
hName := r0 .Host
@@ -322,7 +358,7 @@ func (c *ControlServer) ingressChanged(old *v1beta1.Ingress, new *v1beta1.Ingres
322
358
323
359
}
324
360
325
- func (c * ControlServer ) doDelete (oldIng * v1beta1 .Ingress ) error {
361
+ func (c * ControlServer ) doDelete (oldIng * netv1beta1 .Ingress ) error {
326
362
for _ , r0 := range oldIng .Spec .Rules {
327
363
for _ , p := range r0 .HTTP .Paths {
328
364
sid := c .generateIngressID (oldIng .Name , oldIng .Namespace , p )
@@ -339,7 +375,7 @@ func (c *ControlServer) doDelete(oldIng *v1beta1.Ingress) error {
339
375
}
340
376
341
377
func (c * ControlServer ) handleIngressDelete (obj interface {}) {
342
- ing , ok := obj .( * v1beta1. Ingress )
378
+ ing , ok := convertIngress ( obj )
343
379
if ! ok {
344
380
log .Errorf ("type not allowed: %v" , reflect .TypeOf (obj ))
345
381
return
@@ -355,7 +391,7 @@ func (c *ControlServer) handleIngressDelete(obj interface{}) {
355
391
}
356
392
}
357
393
358
- func (c * ControlServer ) checkIngressManaged (ing * v1beta1 .Ingress ) bool {
394
+ func (c * ControlServer ) checkIngressManaged (ing * netv1beta1 .Ingress ) bool {
359
395
for k , v := range ing .Annotations {
360
396
if k == IngressAnnotation {
361
397
if strings .ToLower (v ) == IngressAnnotationValue {
@@ -367,46 +403,78 @@ func (c *ControlServer) checkIngressManaged(ing *v1beta1.Ingress) bool {
367
403
return false
368
404
}
369
405
370
- func (c * ControlServer ) watchIngresses () {
371
- log .Info ("Watching for ingress activity" )
372
- watchList := cache .NewListWatchFromClient (c .client .ExtensionsV1beta1 ().RESTClient (), "ingresses" , v1 .NamespaceAll ,
373
- fields .Everything ())
374
- c .store , c .ingressController = cache .NewInformer (
375
- watchList ,
376
- & v1beta1.Ingress {},
377
- time .Second * 10 ,
378
- cache.ResourceEventHandlerFuncs {
406
+ // Checks whether k8s version is 1.14+ and therefore uses networking API for ingresses
407
+ func (c * ControlServer ) setNetworkingIngress () {
408
+ version114 , err := version .ParseGeneric ("v1.14.0" )
409
+ if err != nil {
410
+ log .Errorf ("error parsing version: %v" , err )
411
+ return
412
+ }
413
+
414
+ discoveredVersion , err := c .client .Discovery ().ServerVersion ()
415
+ if err != nil {
416
+ log .Errorf ("error discovering k8s version: %v" , err )
417
+ return
418
+ }
419
+
420
+ k8sVersion , err := version .ParseGeneric (discoveredVersion .String ())
421
+ if err != nil {
422
+ log .Errorf ("error parsing discovered k8s version: %v" , err )
423
+ return
424
+ }
425
+
426
+ c .isNetworkingIngress = k8sVersion .AtLeast (version114 )
427
+ }
428
+
429
+ // Watches k8s resources required for ingress controller operations using shared informers
430
+ func (c * ControlServer ) watchAll () error {
431
+ namespaces := c .cfg .WatchNamespaces
432
+ if len (namespaces ) == 0 {
433
+ namespaces = []string {v1 .NamespaceAll }
434
+ }
435
+
436
+ for _ , ns := range namespaces {
437
+ log .Infof ("Registering informers for namespace %s" , ns )
438
+ factory := informers .NewSharedInformerFactoryWithOptions (c .client , defaultResync , informers .WithNamespace (ns ))
439
+
440
+ // Watch ingresses
441
+ var ingressesInformer cache.SharedIndexInformer
442
+ if c .isNetworkingIngress {
443
+ ingressesInformer = factory .Networking ().V1beta1 ().Ingresses ().Informer ()
444
+ } else {
445
+ ingressesInformer = factory .Extensions ().V1beta1 ().Ingresses ().Informer ()
446
+ log .Info ("Using deprecated extensions/v1beta1 ingresses API" )
447
+ }
448
+ ingressesInformer .AddEventHandler (cache.ResourceEventHandlerFuncs {
379
449
AddFunc : c .handleIngressAdd ,
380
450
UpdateFunc : c .handleIngressUpdate ,
381
451
DeleteFunc : c .handleIngressDelete ,
382
- },
383
- )
452
+ })
384
453
385
- c .stopCh = make (chan struct {})
386
- go c .ingressController .Run (c .stopCh )
387
- }
388
-
389
- func (c * ControlServer ) watchPods () {
390
- log .Info ("Watching for pod deletion" )
391
- watchList := cache .NewListWatchFromClient (c .client .CoreV1 ().RESTClient (), "pods" , v1 .NamespaceAll ,
392
- fields .Everything ())
393
- c .store , c .podController = cache .NewInformer (
394
- watchList ,
395
- & v1.Pod {},
396
- time .Second * 10 ,
397
- cache.ResourceEventHandlerFuncs {
454
+ // Watch pods
455
+ factory .Core ().V1 ().Pods ().Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
456
+ AddFunc : nil ,
457
+ UpdateFunc : nil ,
398
458
DeleteFunc : c .handlePodDelete ,
399
- },
400
- )
459
+ })
460
+
461
+ c .factories [ns ] = factory
462
+ factory .Start (c .stopCh )
401
463
402
- c .stopCh = make (chan struct {})
403
- go c .podController .Run (c .stopCh )
464
+ for t , ok := range factory .WaitForCacheSync (c .stopCh ) {
465
+ if ! ok {
466
+ return fmt .Errorf ("failed while syncing %s caches for ns %s" , t .String (), ns )
467
+ }
468
+ }
469
+ }
470
+
471
+ return nil
404
472
}
405
473
406
474
func (c * ControlServer ) handlePodDeleteForMesh (pd * v1.Pod ) {
407
475
log .Info ("pod is injector-managed" )
408
476
409
- remPds , err := c .client .CoreV1 ().Pods (pd .Namespace ).List (v12 .ListOptions {})
477
+ remPds , err := c .client .CoreV1 ().Pods (pd .Namespace ).List (metav1 .ListOptions {})
410
478
if err != nil {
411
479
log .Error (err )
412
480
}
0 commit comments