@@ -2,7 +2,6 @@ package clusterquotamapping
2
2
3
3
import (
4
4
"fmt"
5
- "sync"
6
5
"time"
7
6
8
7
"github.com/golang/glog"
@@ -15,7 +14,6 @@ import (
15
14
"k8s.io/kubernetes/pkg/controller/framework"
16
15
"k8s.io/kubernetes/pkg/labels"
17
16
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
18
- "k8s.io/kubernetes/pkg/util/sets"
19
17
"k8s.io/kubernetes/pkg/util/wait"
20
18
"k8s.io/kubernetes/pkg/util/workqueue"
21
19
@@ -24,15 +22,6 @@ import (
24
22
quotaapi "github.com/openshift/origin/pkg/quota/api"
25
23
)
26
24
27
- type ClusterQuotaMapper interface {
28
- // GetClusterQuotasFor returns the list of clusterquota names that this namespace matches. It also
29
- // returns the labels associated with the namespace for the check so that callers can determine staleness
30
- GetClusterQuotasFor (namespaceName string ) ([]string , map [string ]string )
31
- // GetNamespacesFor returns the list of namespace names that this cluster quota matches. It also
32
- // returns the selector associated with the clusterquota for the check so that callers can determine staleness
33
- GetNamespacesFor (quotaName string ) ([]string , * unversioned.LabelSelector )
34
- }
35
-
36
25
// Look out, here there be dragons!
37
26
// There is a race when dealing with the DeltaFifo compression used to back a reflector for a controller that uses two
38
27
// SharedInformers for both their watch events AND their caches. The scenario looks like this
@@ -65,15 +54,7 @@ func NewClusterQuotaMappingController(namespaceInformer shared.NamespaceInformer
65
54
66
55
quotaQueue : workqueue .NewRateLimitingQueue (workqueue .DefaultControllerRateLimiter ()),
67
56
68
- clusterQuotaMapper : & clusterQuotaMapper {
69
- requiredQuotaToSelector : map [string ]* unversioned.LabelSelector {},
70
- requiredNamespaceToLabels : map [string ]map [string ]string {},
71
- completedQuotaToSelector : map [string ]* unversioned.LabelSelector {},
72
- completedNamespaceToLabels : map [string ]map [string ]string {},
73
-
74
- quotaToNamespaces : map [string ]sets.String {},
75
- namespaceToQuota : map [string ]sets.String {},
76
- },
57
+ clusterQuotaMapper : NewClusterQuotaMapper (),
77
58
}
78
59
79
60
namespaceInformer .Informer ().AddEventHandler (framework.ResourceEventHandlerFuncs {
@@ -107,204 +88,6 @@ type ClusterQuotaMappingController struct {
107
88
clusterQuotaMapper * clusterQuotaMapper
108
89
}
109
90
110
- // clusterQuotaMapper gives thread safe access to the actual mappings that are being stored.
111
- // Many method use a shareable read lock to check status followed by a non-shareable
112
- // write lock which double checks the condition before proceding. Since locks aren't escalatable
113
- // you have to perform the recheck because someone could have beaten you in.
114
- type clusterQuotaMapper struct {
115
- lock sync.RWMutex
116
-
117
- // requiredQuotaToSelector indicates the latest label selector this controller has observed for a quota
118
- requiredQuotaToSelector map [string ]* unversioned.LabelSelector
119
- // requiredNamespaceToLabels indicates the latest labels this controller has observed for a namespace
120
- requiredNamespaceToLabels map [string ]map [string ]string
121
- // completedQuotaToSelector indicates the latest label selector this controller has scanned against namespaces
122
- completedQuotaToSelector map [string ]* unversioned.LabelSelector
123
- // completedNamespaceToLabels indicates the latest labels this controller has scanned against cluster quotas
124
- completedNamespaceToLabels map [string ]map [string ]string
125
-
126
- quotaToNamespaces map [string ]sets.String
127
- namespaceToQuota map [string ]sets.String
128
- }
129
-
130
- func (m * clusterQuotaMapper ) GetClusterQuotasFor (namespaceName string ) ([]string , map [string ]string ) {
131
- m .lock .RLock ()
132
- defer m .lock .RUnlock ()
133
-
134
- quotas , ok := m .namespaceToQuota [namespaceName ]
135
- if ! ok {
136
- return []string {}, m .completedNamespaceToLabels [namespaceName ]
137
- }
138
- return quotas .List (), m .completedNamespaceToLabels [namespaceName ]
139
- }
140
-
141
- func (m * clusterQuotaMapper ) GetNamespacesFor (quotaName string ) ([]string , * unversioned.LabelSelector ) {
142
- m .lock .RLock ()
143
- defer m .lock .RUnlock ()
144
-
145
- namespaces , ok := m .quotaToNamespaces [quotaName ]
146
- if ! ok {
147
- return []string {}, m .completedQuotaToSelector [quotaName ]
148
- }
149
- return namespaces .List (), m .completedQuotaToSelector [quotaName ]
150
- }
151
-
152
- // requireQuota updates the selector requirements for the given quota. This prevents stale updates to the mapping itself.
153
- // returns true if a modification was made
154
- func (m * clusterQuotaMapper ) requireQuota (quota * quotaapi.ClusterResourceQuota ) bool {
155
- m .lock .RLock ()
156
- selector , exists := m .requiredQuotaToSelector [quota .Name ]
157
- m .lock .RUnlock ()
158
-
159
- if selectorMatches (selector , exists , quota ) {
160
- return false
161
- }
162
-
163
- m .lock .Lock ()
164
- defer m .lock .Unlock ()
165
- selector , exists = m .requiredQuotaToSelector [quota .Name ]
166
- if selectorMatches (selector , exists , quota ) {
167
- return false
168
- }
169
-
170
- m .requiredQuotaToSelector [quota .Name ] = quota .Spec .Selector
171
- return true
172
- }
173
-
174
- // completeQuota updates the latest selector used to generate the mappings for this quota. The value is returned
175
- // by the Get methods for the mapping so that callers can determine staleness
176
- func (m * clusterQuotaMapper ) completeQuota (quota * quotaapi.ClusterResourceQuota ) {
177
- m .lock .Lock ()
178
- defer m .lock .Unlock ()
179
- m .completedQuotaToSelector [quota .Name ] = quota .Spec .Selector
180
- }
181
-
182
- // removeQuota deletes a quota from all mappings
183
- func (m * clusterQuotaMapper ) removeQuota (quotaName string ) {
184
- m .lock .Lock ()
185
- defer m .lock .Unlock ()
186
-
187
- delete (m .requiredQuotaToSelector , quotaName )
188
- delete (m .completedQuotaToSelector , quotaName )
189
- delete (m .quotaToNamespaces , quotaName )
190
- for _ , quotas := range m .namespaceToQuota {
191
- quotas .Delete (quotaName )
192
- }
193
- }
194
-
195
- // requireNamespace updates the label requirements for the given namespace. This prevents stale updates to the mapping itself.
196
- // returns true if a modification was made
197
- func (m * clusterQuotaMapper ) requireNamespace (namespace * kapi.Namespace ) bool {
198
- m .lock .RLock ()
199
- labels , exists := m .requiredNamespaceToLabels [namespace .Name ]
200
- m .lock .RUnlock ()
201
-
202
- if labelsMatch (labels , exists , namespace ) {
203
- return false
204
- }
205
-
206
- m .lock .Lock ()
207
- defer m .lock .Unlock ()
208
- labels , exists = m .requiredNamespaceToLabels [namespace .Name ]
209
- if labelsMatch (labels , exists , namespace ) {
210
- return false
211
- }
212
-
213
- m .requiredNamespaceToLabels [namespace .Name ] = namespace .Labels
214
- return true
215
- }
216
-
217
- // completeNamespace updates the latest labels used to generate the mappings for this namespace. The value is returned
218
- // by the Get methods for the mapping so that callers can determine staleness
219
- func (m * clusterQuotaMapper ) completeNamespace (namespace * kapi.Namespace ) {
220
- m .lock .Lock ()
221
- defer m .lock .Unlock ()
222
- m .completedNamespaceToLabels [namespace .Name ] = namespace .Labels
223
- }
224
-
225
- // removeNamespace deletes a namespace from all mappings
226
- func (m * clusterQuotaMapper ) removeNamespace (namespaceName string ) {
227
- m .lock .Lock ()
228
- defer m .lock .Unlock ()
229
-
230
- delete (m .requiredNamespaceToLabels , namespaceName )
231
- delete (m .completedNamespaceToLabels , namespaceName )
232
- delete (m .namespaceToQuota , namespaceName )
233
- for _ , namespaces := range m .quotaToNamespaces {
234
- namespaces .Delete (namespaceName )
235
- }
236
- }
237
-
238
- func selectorMatches (selector * unversioned.LabelSelector , exists bool , quota * quotaapi.ClusterResourceQuota ) bool {
239
- return exists && kapi .Semantic .DeepEqual (selector , quota .Spec .Selector )
240
- }
241
- func labelsMatch (labels map [string ]string , exists bool , namespace * kapi.Namespace ) bool {
242
- return exists && kapi .Semantic .DeepEqual (labels , namespace .Labels )
243
- }
244
-
245
- // setMapping maps (or removes a mapping) between a clusterquota and a namespace
246
- // It returns whether the action worked, whether the quota is out of date, whether the namespace is out of date
247
- // This allows callers to decide whether to pull new information from the cache or simply skip execution
248
- func (m * clusterQuotaMapper ) setMapping (quota * quotaapi.ClusterResourceQuota , namespace * kapi.Namespace , remove bool ) (bool /*added*/ , bool /*quota matches*/ , bool /*namespace matches*/ ) {
249
- m .lock .RLock ()
250
- selector , selectorExists := m .requiredQuotaToSelector [quota .Name ]
251
- labels , labelsExist := m .requiredNamespaceToLabels [namespace .Name ]
252
- m .lock .RUnlock ()
253
-
254
- if ! selectorMatches (selector , selectorExists , quota ) {
255
- return false , false , true
256
- }
257
- if ! labelsMatch (labels , labelsExist , namespace ) {
258
- return false , true , false
259
- }
260
-
261
- m .lock .Lock ()
262
- defer m .lock .Unlock ()
263
- selector , selectorExists = m .requiredQuotaToSelector [quota .Name ]
264
- labels , labelsExist = m .requiredNamespaceToLabels [namespace .Name ]
265
- if ! selectorMatches (selector , selectorExists , quota ) {
266
- return false , false , true
267
- }
268
- if ! labelsMatch (labels , labelsExist , namespace ) {
269
- return false , true , false
270
- }
271
-
272
- if remove {
273
- namespaces , ok := m .quotaToNamespaces [quota .Name ]
274
- if ! ok {
275
- m .quotaToNamespaces [quota .Name ] = sets.String {}
276
- } else {
277
- namespaces .Delete (namespace .Name )
278
- }
279
-
280
- quotas , ok := m .namespaceToQuota [namespace .Name ]
281
- if ! ok {
282
- m .namespaceToQuota [namespace .Name ] = sets.String {}
283
- } else {
284
- quotas .Delete (quota .Name )
285
- }
286
-
287
- return true , true , true
288
- }
289
-
290
- namespaces , ok := m .quotaToNamespaces [quota .Name ]
291
- if ! ok {
292
- m .quotaToNamespaces [quota .Name ] = sets .NewString (namespace .Name )
293
- } else {
294
- namespaces .Insert (namespace .Name )
295
- }
296
-
297
- quotas , ok := m .namespaceToQuota [namespace .Name ]
298
- if ! ok {
299
- m .namespaceToQuota [namespace .Name ] = sets .NewString (quota .Name )
300
- } else {
301
- quotas .Insert (quota .Name )
302
- }
303
-
304
- return true , true , true
305
-
306
- }
307
-
308
91
func (c * ClusterQuotaMappingController ) GetClusterQuotaMapper () ClusterQuotaMapper {
309
92
return c .clusterQuotaMapper
310
93
}
0 commit comments