@@ -117,9 +117,6 @@ type InformersMap struct {
117
117
// paramCodec is used by list and watch
118
118
paramCodec runtime.ParameterCodec
119
119
120
- // stop is the stop channel to stop informers
121
- stop <- chan struct {}
122
-
123
120
// resync is the base frequency the informers are resynced
124
121
// a 10 percent jitter will be added to the resync period between informers
125
122
// so that all informers will not send list requests simultaneously.
@@ -128,13 +125,22 @@ type InformersMap struct {
128
125
// mu guards access to the map
129
126
mu sync.RWMutex
130
127
131
- // start is true if the informers have been started
128
+ // started is true if the informers have been started
132
129
started bool
133
130
134
131
// startWait is a channel that is closed after the
135
132
// informer has been started.
136
133
startWait chan struct {}
137
134
135
+ // waitGroup is the wait group that is used to wait for all informers to stop
136
+ waitGroup sync.WaitGroup
137
+
138
+ // stopped is true if the informers have been stopped
139
+ stopped bool
140
+
141
+ // ctx is the context to stop informers
142
+ ctx context.Context
143
+
138
144
// namespace is the namespace that all ListWatches are restricted to
139
145
// default or empty string means all namespaces
140
146
namespace string
@@ -158,24 +164,42 @@ func (ip *InformersMap) Start(ctx context.Context) error {
158
164
defer ip .mu .Unlock ()
159
165
160
166
// Set the stop channel so it can be passed to informers that are added later
161
- ip .stop = ctx .Done ()
167
+ ip .ctx = ctx
168
+
169
+ ip .waitGroup .Add (len (ip .informers .Structured ) + len (ip .informers .Unstructured ) + len (ip .informers .Metadata ))
162
170
163
171
// Start each informer
164
172
for _ , i := range ip .informers .Structured {
165
- go i .Informer .Run (ctx .Done ())
173
+ i := i
174
+ go func () {
175
+ defer ip .waitGroup .Done ()
176
+ i .Informer .Run (ctx .Done ())
177
+ }()
166
178
}
167
179
for _ , i := range ip .informers .Unstructured {
168
- go i .Informer .Run (ctx .Done ())
180
+ i := i
181
+ go func () {
182
+ defer ip .waitGroup .Done ()
183
+ i .Informer .Run (ctx .Done ())
184
+ }()
169
185
}
170
186
for _ , i := range ip .informers .Metadata {
171
- go i .Informer .Run (ctx .Done ())
187
+ i := i
188
+ go func () {
189
+ defer ip .waitGroup .Done ()
190
+ i .Informer .Run (ctx .Done ())
191
+ }()
172
192
}
173
193
174
194
// Set started to true so we immediately start any informers added later.
175
195
ip .started = true
176
196
close (ip .startWait )
177
197
}()
178
- <- ctx .Done ()
198
+ <- ctx .Done () // Block until the context is done
199
+ ip .mu .Lock ()
200
+ ip .stopped = true // Set stopped to true so we don't start any new informers
201
+ ip .mu .Unlock ()
202
+ ip .waitGroup .Wait () // Block until all informers have stopped
179
203
return nil
180
204
}
181
205
@@ -310,17 +334,17 @@ func (ip *InformersMap) addInformerToMap(gvk schema.GroupVersionKind, obj runtim
310
334
// Start the Informer if need by
311
335
// TODO(seans): write thorough tests and document what happens here - can you add indexers?
312
336
// can you add eventhandlers?
313
- if ip .started {
314
- go i .Informer .Run (ip .stop )
337
+ if ip .started && ! ip .stopped {
338
+ ip .waitGroup .Add (1 )
339
+ go func () {
340
+ defer ip .waitGroup .Done ()
341
+ i .Informer .Run (ip .ctx .Done ())
342
+ }()
315
343
}
316
344
return i , ip .started , nil
317
345
}
318
346
319
347
func (ip * InformersMap ) makeListWatcher (gvk schema.GroupVersionKind , obj runtime.Object ) (* cache.ListWatch , error ) {
320
- // TODO(vincepri): Wire the context in here and don't use TODO().
321
- // Can we use the context from the Get call?
322
- ctx := context .TODO ()
323
-
324
348
// Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
325
349
// groupVersionKind to the Resource API we will use.
326
350
mapping , err := ip .mapper .RESTMapping (gvk .GroupKind (), gvk .Version )
@@ -351,16 +375,16 @@ func (ip *InformersMap) makeListWatcher(gvk schema.GroupVersionKind, obj runtime
351
375
return & cache.ListWatch {
352
376
ListFunc : func (opts metav1.ListOptions ) (runtime.Object , error ) {
353
377
if namespace != "" {
354
- return resources .Namespace (namespace ).List (ctx , opts )
378
+ return resources .Namespace (namespace ).List (ip . ctx , opts )
355
379
}
356
- return resources .List (ctx , opts )
380
+ return resources .List (ip . ctx , opts )
357
381
},
358
382
// Setup the watch function
359
383
WatchFunc : func (opts metav1.ListOptions ) (watch.Interface , error ) {
360
384
if namespace != "" {
361
- return resources .Namespace (namespace ).Watch (ctx , opts )
385
+ return resources .Namespace (namespace ).Watch (ip . ctx , opts )
362
386
}
363
- return resources .Watch (ctx , opts )
387
+ return resources .Watch (ip . ctx , opts )
364
388
},
365
389
}, nil
366
390
//
@@ -386,9 +410,9 @@ func (ip *InformersMap) makeListWatcher(gvk schema.GroupVersionKind, obj runtime
386
410
err error
387
411
)
388
412
if namespace != "" {
389
- list , err = resources .Namespace (namespace ).List (ctx , opts )
413
+ list , err = resources .Namespace (namespace ).List (ip . ctx , opts )
390
414
} else {
391
- list , err = resources .List (ctx , opts )
415
+ list , err = resources .List (ip . ctx , opts )
392
416
}
393
417
if list != nil {
394
418
for i := range list .Items {
@@ -400,9 +424,9 @@ func (ip *InformersMap) makeListWatcher(gvk schema.GroupVersionKind, obj runtime
400
424
// Setup the watch function
401
425
WatchFunc : func (opts metav1.ListOptions ) (watcher watch.Interface , err error ) {
402
426
if namespace != "" {
403
- watcher , err = resources .Namespace (namespace ).Watch (ctx , opts )
427
+ watcher , err = resources .Namespace (namespace ).Watch (ip . ctx , opts )
404
428
} else {
405
- watcher , err = resources .Watch (ctx , opts )
429
+ watcher , err = resources .Watch (ip . ctx , opts )
406
430
}
407
431
if err != nil {
408
432
return nil , err
@@ -433,7 +457,7 @@ func (ip *InformersMap) makeListWatcher(gvk schema.GroupVersionKind, obj runtime
433
457
434
458
// Create the resulting object, and execute the request.
435
459
res := listObj .DeepCopyObject ()
436
- if err := req .Do (ctx ).Into (res ); err != nil {
460
+ if err := req .Do (ip . ctx ).Into (res ); err != nil {
437
461
return nil , err
438
462
}
439
463
return res , nil
@@ -446,7 +470,7 @@ func (ip *InformersMap) makeListWatcher(gvk schema.GroupVersionKind, obj runtime
446
470
req .Namespace (namespace )
447
471
}
448
472
// Call the watch.
449
- return req .Watch (ctx )
473
+ return req .Watch (ip . ctx )
450
474
},
451
475
}, nil
452
476
}
0 commit comments