@@ -23,6 +23,7 @@ import (
23
23
24
24
"k8s.io/apimachinery/pkg/api/meta"
25
25
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
26
27
"k8s.io/apimachinery/pkg/runtime"
27
28
"k8s.io/apimachinery/pkg/runtime/schema"
28
29
"k8s.io/apimachinery/pkg/runtime/serializer"
@@ -38,13 +39,14 @@ func NewInformersMap(config *rest.Config,
38
39
mapper meta.RESTMapper ,
39
40
resync time.Duration ) * InformersMap {
40
41
ip := & InformersMap {
41
- config : config ,
42
- Scheme : scheme ,
43
- mapper : mapper ,
44
- informersByGVK : make (map [schema.GroupVersionKind ]* MapEntry ),
45
- codecs : serializer .NewCodecFactory (scheme ),
46
- paramCodec : runtime .NewParameterCodec (scheme ),
47
- resync : resync ,
42
+ config : config ,
43
+ Scheme : scheme ,
44
+ mapper : mapper ,
45
+ informersByGVK : make (map [schema.GroupVersionKind ]* MapEntry ),
46
+ unstructuredInformerByGVK : make (map [schema.GroupVersionKind ]* MapEntry ),
47
+ codecs : serializer .NewCodecFactory (scheme ),
48
+ paramCodec : runtime .NewParameterCodec (scheme ),
49
+ resync : resync ,
48
50
}
49
51
return ip
50
52
}
@@ -73,6 +75,10 @@ type InformersMap struct {
73
75
// informersByGVK is the cache of informers keyed by groupVersionKind
74
76
informersByGVK map [schema.GroupVersionKind ]* MapEntry
75
77
78
+ // unstructuredInformerByGVK is a cache of informers for unstructured types
79
+ // keyed by groupVersionKind
80
+ unstructuredInformerByGVK map [schema.GroupVersionKind ]* MapEntry
81
+
76
82
// codecs is used to create a new REST client
77
83
codecs serializer.CodecFactory
78
84
@@ -87,6 +93,8 @@ type InformersMap struct {
87
93
88
94
// mu guards access to the map
89
95
mu sync.RWMutex
96
+ // mu guards access to the unstructured map
97
+ unstructuredMu sync.RWMutex
90
98
91
99
// start is true if the informers have been started
92
100
started bool
@@ -96,7 +104,9 @@ type InformersMap struct {
96
104
func (ip * InformersMap ) Start (stop <- chan struct {}) error {
97
105
func () {
98
106
ip .mu .Lock ()
107
+ ip .unstructuredMu .Lock ()
99
108
defer ip .mu .Unlock ()
109
+ defer ip .unstructuredMu .Unlock ()
100
110
101
111
// Set the stop channel so it can be passed to informers that are added later
102
112
ip .stop = stop
@@ -106,6 +116,11 @@ func (ip *InformersMap) Start(stop <-chan struct{}) error {
106
116
go informer .Informer .Run (stop )
107
117
}
108
118
119
+ // Start each unstructured informer
120
+ for _ , informer := range ip .unstructuredInformerByGVK {
121
+ go informer .Informer .Run (stop )
122
+ }
123
+
109
124
// Set started to true so we immediately start any informers added later.
110
125
ip .started = true
111
126
}()
@@ -115,23 +130,36 @@ func (ip *InformersMap) Start(stop <-chan struct{}) error {
115
130
116
131
// WaitForCacheSync waits until all the caches have been synced
117
132
func (ip * InformersMap ) WaitForCacheSync (stop <- chan struct {}) bool {
118
- syncedFuncs := make ([]cache.InformerSynced , 0 , len (ip .informersByGVK ))
133
+ syncedFuncs := make ([]cache.InformerSynced , 0 , len (ip .informersByGVK )+ len ( ip . unstructuredInformerByGVK ) )
119
134
for _ , informer := range ip .informersByGVK {
120
135
syncedFuncs = append (syncedFuncs , informer .Informer .HasSynced )
121
136
}
137
+ for _ , informer := range ip .unstructuredInformerByGVK {
138
+ syncedFuncs = append (syncedFuncs , informer .Informer .HasSynced )
139
+ }
122
140
return cache .WaitForCacheSync (stop , syncedFuncs ... )
123
141
}
124
142
143
+ func (ip * InformersMap ) getMapEntry (gvk schema.GroupVersionKind , isUnstructured bool ) (* MapEntry , bool ) {
144
+ if isUnstructured {
145
+ ip .unstructuredMu .RLock ()
146
+ defer ip .unstructuredMu .RUnlock ()
147
+ i , ok := ip .unstructuredInformerByGVK [gvk ]
148
+ return i , ok
149
+ }
150
+ ip .mu .RLock ()
151
+ defer ip .mu .RUnlock ()
152
+ i , ok := ip .informersByGVK [gvk ]
153
+ return i , ok
154
+
155
+ }
156
+
125
157
// Get will create a new Informer and add it to the map of InformersMap if none exists. Returns
126
158
// the Informer from the map.
127
159
func (ip * InformersMap ) Get (gvk schema.GroupVersionKind , obj runtime.Object ) (* MapEntry , error ) {
160
+ _ , isUnstructured := obj .(* unstructured.Unstructured )
128
161
// Return the informer if it is found
129
- i , ok := func () (* MapEntry , bool ) {
130
- ip .mu .RLock ()
131
- defer ip .mu .RUnlock ()
132
- i , ok := ip .informersByGVK [gvk ]
133
- return i , ok
134
- }()
162
+ i , ok := ip .getMapEntry (gvk , isUnstructured )
135
163
if ok {
136
164
return i , nil
137
165
}
@@ -140,21 +168,27 @@ func (ip *InformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Object) (*M
140
168
// need to be locked
141
169
var sync bool
142
170
i , err := func () (* MapEntry , error ) {
143
- ip .mu .Lock ()
144
- defer ip .mu .Unlock ()
145
-
146
- // Check the cache to see if we already have an Informer. If we do, return the Informer.
171
+ var ok bool
172
+ var i * MapEntry
173
+ // Check the caches to see if we already have an Informer. If we do, return the Informer.
147
174
// This is for the case where 2 routines tried to get the informer when it wasn't in the map
148
175
// so neither returned early, but the first one created it.
149
- var ok bool
150
- i , ok := ip .informersByGVK [gvk ]
176
+ if isUnstructured {
177
+ ip .unstructuredMu .Lock ()
178
+ defer ip .unstructuredMu .Unlock ()
179
+ i , ok = ip .unstructuredInformerByGVK [gvk ]
180
+ } else {
181
+ ip .mu .Lock ()
182
+ defer ip .mu .Unlock ()
183
+ i , ok = ip .informersByGVK [gvk ]
184
+ }
151
185
if ok {
152
186
return i , nil
153
187
}
154
188
155
189
// Create a NewSharedIndexInformer and add it to the map.
156
190
var lw * cache.ListWatch
157
- lw , err := ip .newListWatch (gvk )
191
+ lw , err := ip .newListWatch (gvk , isUnstructured )
158
192
if err != nil {
159
193
return nil , err
160
194
}
@@ -191,26 +225,34 @@ func (ip *InformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Object) (*M
191
225
}
192
226
193
227
// newListWatch returns a new ListWatch object that can be used to create a SharedIndexInformer.
194
- func (ip * InformersMap ) newListWatch (gvk schema.GroupVersionKind ) (* cache.ListWatch , error ) {
195
- // Construct a RESTClient for the groupVersionKind that we will use to
196
- // talk to the apiserver.
197
- client , err := apiutil .RESTClientForGVK (gvk , ip .config , ip .codecs )
198
- if err != nil {
199
- return nil , err
200
- }
201
-
228
+ func (ip * InformersMap ) newListWatch (gvk schema.GroupVersionKind , isUnstructured bool ) (* cache.ListWatch , error ) {
202
229
// Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
203
230
// groupVersionKind to the Resource API we will use.
204
231
mapping , err := ip .mapper .RESTMapping (gvk .GroupKind (), gvk .Version )
205
232
if err != nil {
206
233
return nil , err
207
234
}
208
235
209
- // Get a listObject for listing that the ListWatch can DeepCopy
210
- listGVK := gvk .GroupVersion ().WithKind (gvk .Kind + "List" )
211
- listObj , err := ip .Scheme .New (listGVK )
212
- if err != nil {
213
- return nil , err
236
+ // Construct a RESTClient for the groupVersionKind that we will use to
237
+ // talk to the apiserver.
238
+ var client rest.Interface
239
+ var listObj runtime.Object
240
+ if isUnstructured {
241
+ listObj = & unstructured.UnstructuredList {}
242
+ client , err = apiutil .RESTUnstructuredClientForGVK (gvk , ip .config )
243
+ if err != nil {
244
+ return nil , err
245
+ }
246
+ } else {
247
+ client , err = apiutil .RESTClientForGVK (gvk , ip .config , ip .codecs )
248
+ if err != nil {
249
+ return nil , err
250
+ }
251
+ listGVK := gvk .GroupVersion ().WithKind (gvk .Kind + "List" )
252
+ listObj , err = ip .Scheme .New (listGVK )
253
+ if err != nil {
254
+ return nil , err
255
+ }
214
256
}
215
257
216
258
// Create a new ListWatch for the obj
0 commit comments