@@ -26,7 +26,9 @@ import (
26
26
policy "k8s.io/api/policy/v1beta1"
27
27
apiequality "k8s.io/apimachinery/pkg/api/equality"
28
28
"k8s.io/apimachinery/pkg/api/errors"
29
+ apimeta "k8s.io/apimachinery/pkg/api/meta"
29
30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31
+ "k8s.io/apimachinery/pkg/runtime/schema"
30
32
"k8s.io/apimachinery/pkg/types"
31
33
"k8s.io/apimachinery/pkg/util/intstr"
32
34
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@@ -41,6 +43,7 @@ import (
41
43
appsv1listers "k8s.io/client-go/listers/apps/v1"
42
44
corelisters "k8s.io/client-go/listers/core/v1"
43
45
policylisters "k8s.io/client-go/listers/policy/v1beta1"
46
+ scaleclient "k8s.io/client-go/scale"
44
47
"k8s.io/client-go/tools/cache"
45
48
"k8s.io/client-go/tools/record"
46
49
"k8s.io/client-go/util/workqueue"
@@ -67,6 +70,9 @@ type updater func(*policy.PodDisruptionBudget) error
67
70
68
71
type DisruptionController struct {
69
72
kubeClient clientset.Interface
73
+ mapper apimeta.RESTMapper
74
+
75
+ scaleNamespacer scaleclient.ScalesGetter
70
76
71
77
pdbLister policylisters.PodDisruptionBudgetLister
72
78
pdbListerSynced cache.InformerSynced
@@ -105,7 +111,7 @@ type controllerAndScale struct {
105
111
106
112
// podControllerFinder is a function type that maps a pod to a list of
107
113
// controllers and their scale.
108
- type podControllerFinder func (* v1. Pod ) (* controllerAndScale , error )
114
+ type podControllerFinder func (controllerRef * metav1. OwnerReference , namespace string ) (* controllerAndScale , error )
109
115
110
116
func NewDisruptionController (
111
117
podInformer coreinformers.PodInformer ,
@@ -115,6 +121,8 @@ func NewDisruptionController(
115
121
dInformer appsv1informers.DeploymentInformer ,
116
122
ssInformer appsv1informers.StatefulSetInformer ,
117
123
kubeClient clientset.Interface ,
124
+ restMapper apimeta.RESTMapper ,
125
+ scaleNamespacer scaleclient.ScalesGetter ,
118
126
) * DisruptionController {
119
127
dc := & DisruptionController {
120
128
kubeClient : kubeClient ,
@@ -157,19 +165,19 @@ func NewDisruptionController(
157
165
dc .ssLister = ssInformer .Lister ()
158
166
dc .ssListerSynced = ssInformer .Informer ().HasSynced
159
167
168
+ dc .mapper = restMapper
169
+ dc .scaleNamespacer = scaleNamespacer
170
+
160
171
return dc
161
172
}
162
173
163
- // TODO(mml): When controllerRef is implemented (#2210), we *could* simply
164
- // return controllers without their scales, and access scale type-generically
165
- // via the scale subresource. That may not be as much of a win as it sounds,
166
- // however. We are accessing everything through the pkg/client/cache API that
167
- // we have to set up and tune to the types we know we'll be accessing anyway,
168
- // and we may well need further tweaks just to be able to access scale
169
- // subresources.
174
+ // The workload resources do implement the scale subresource, so it would
175
+ // be possible to only check the scale subresource here. But since there is no
176
+ // way to take advantage of listers with scale subresources, we use the workload
177
+ // resources directly and only fall back to the scale subresource when needed.
170
178
func (dc * DisruptionController ) finders () []podControllerFinder {
171
179
return []podControllerFinder {dc .getPodReplicationController , dc .getPodDeployment , dc .getPodReplicaSet ,
172
- dc .getPodStatefulSet }
180
+ dc .getPodStatefulSet , dc . getScaleController }
173
181
}
174
182
175
183
var (
@@ -180,15 +188,12 @@ var (
180
188
)
181
189
182
190
// getPodReplicaSet finds a replicaset which has no matching deployments.
183
- func (dc * DisruptionController ) getPodReplicaSet (pod * v1. Pod ) (* controllerAndScale , error ) {
184
- controllerRef := metav1 . GetControllerOf ( pod )
185
- if controllerRef = = nil {
186
- return nil , nil
191
+ func (dc * DisruptionController ) getPodReplicaSet (controllerRef * metav1. OwnerReference , namespace string ) (* controllerAndScale , error ) {
192
+ ok , err := verifyGroupKind ( controllerRef , controllerKindRS . Kind , [] string { "apps" , "extensions" } )
193
+ if ! ok || err ! = nil {
194
+ return nil , err
187
195
}
188
- if controllerRef .Kind != controllerKindRS .Kind {
189
- return nil , nil
190
- }
191
- rs , err := dc .rsLister .ReplicaSets (pod .Namespace ).Get (controllerRef .Name )
196
+ rs , err := dc .rsLister .ReplicaSets (namespace ).Get (controllerRef .Name )
192
197
if err != nil {
193
198
// The only possible error is NotFound, which is ok here.
194
199
return nil , nil
@@ -204,16 +209,13 @@ func (dc *DisruptionController) getPodReplicaSet(pod *v1.Pod) (*controllerAndSca
204
209
return & controllerAndScale {rs .UID , * (rs .Spec .Replicas )}, nil
205
210
}
206
211
207
- // getPodStatefulSet returns the statefulset managing the given pod.
208
- func (dc * DisruptionController ) getPodStatefulSet (pod * v1.Pod ) (* controllerAndScale , error ) {
209
- controllerRef := metav1 .GetControllerOf (pod )
210
- if controllerRef == nil {
211
- return nil , nil
212
- }
213
- if controllerRef .Kind != controllerKindSS .Kind {
214
- return nil , nil
212
+ // getPodStatefulSet returns the statefulset referenced by the provided controllerRef.
213
+ func (dc * DisruptionController ) getPodStatefulSet (controllerRef * metav1.OwnerReference , namespace string ) (* controllerAndScale , error ) {
214
+ ok , err := verifyGroupKind (controllerRef , controllerKindSS .Kind , []string {"apps" })
215
+ if ! ok || err != nil {
216
+ return nil , err
215
217
}
216
- ss , err := dc .ssLister .StatefulSets (pod . Namespace ).Get (controllerRef .Name )
218
+ ss , err := dc .ssLister .StatefulSets (namespace ).Get (controllerRef .Name )
217
219
if err != nil {
218
220
// The only possible error is NotFound, which is ok here.
219
221
return nil , nil
@@ -226,15 +228,12 @@ func (dc *DisruptionController) getPodStatefulSet(pod *v1.Pod) (*controllerAndSc
226
228
}
227
229
228
230
// getPodDeployments finds deployments for any replicasets which are being managed by deployments.
229
- func (dc * DisruptionController ) getPodDeployment (pod * v1.Pod ) (* controllerAndScale , error ) {
230
- controllerRef := metav1 .GetControllerOf (pod )
231
- if controllerRef == nil {
232
- return nil , nil
233
- }
234
- if controllerRef .Kind != controllerKindRS .Kind {
235
- return nil , nil
231
+ func (dc * DisruptionController ) getPodDeployment (controllerRef * metav1.OwnerReference , namespace string ) (* controllerAndScale , error ) {
232
+ ok , err := verifyGroupKind (controllerRef , controllerKindRS .Kind , []string {"apps" , "extensions" })
233
+ if ! ok || err != nil {
234
+ return nil , err
236
235
}
237
- rs , err := dc .rsLister .ReplicaSets (pod . Namespace ).Get (controllerRef .Name )
236
+ rs , err := dc .rsLister .ReplicaSets (namespace ).Get (controllerRef .Name )
238
237
if err != nil {
239
238
// The only possible error is NotFound, which is ok here.
240
239
return nil , nil
@@ -246,8 +245,10 @@ func (dc *DisruptionController) getPodDeployment(pod *v1.Pod) (*controllerAndSca
246
245
if controllerRef == nil {
247
246
return nil , nil
248
247
}
249
- if controllerRef .Kind != controllerKindDep .Kind {
250
- return nil , nil
248
+
249
+ ok , err = verifyGroupKind (controllerRef , controllerKindDep .Kind , []string {"apps" , "extensions" })
250
+ if ! ok || err != nil {
251
+ return nil , err
251
252
}
252
253
deployment , err := dc .dLister .Deployments (rs .Namespace ).Get (controllerRef .Name )
253
254
if err != nil {
@@ -260,15 +261,12 @@ func (dc *DisruptionController) getPodDeployment(pod *v1.Pod) (*controllerAndSca
260
261
return & controllerAndScale {deployment .UID , * (deployment .Spec .Replicas )}, nil
261
262
}
262
263
263
- func (dc * DisruptionController ) getPodReplicationController (pod * v1.Pod ) (* controllerAndScale , error ) {
264
- controllerRef := metav1 .GetControllerOf (pod )
265
- if controllerRef == nil {
266
- return nil , nil
267
- }
268
- if controllerRef .Kind != controllerKindRC .Kind {
269
- return nil , nil
264
+ func (dc * DisruptionController ) getPodReplicationController (controllerRef * metav1.OwnerReference , namespace string ) (* controllerAndScale , error ) {
265
+ ok , err := verifyGroupKind (controllerRef , controllerKindRC .Kind , []string {"" })
266
+ if ! ok || err != nil {
267
+ return nil , err
270
268
}
271
- rc , err := dc .rcLister .ReplicationControllers (pod . Namespace ).Get (controllerRef .Name )
269
+ rc , err := dc .rcLister .ReplicationControllers (namespace ).Get (controllerRef .Name )
272
270
if err != nil {
273
271
// The only possible error is NotFound, which is ok here.
274
272
return nil , nil
@@ -279,6 +277,55 @@ func (dc *DisruptionController) getPodReplicationController(pod *v1.Pod) (*contr
279
277
return & controllerAndScale {rc .UID , * (rc .Spec .Replicas )}, nil
280
278
}
281
279
280
+ func (dc * DisruptionController ) getScaleController (controllerRef * metav1.OwnerReference , namespace string ) (* controllerAndScale , error ) {
281
+ gv , err := schema .ParseGroupVersion (controllerRef .APIVersion )
282
+ if err != nil {
283
+ return nil , err
284
+ }
285
+
286
+ gk := schema.GroupKind {
287
+ Group : gv .Group ,
288
+ Kind : controllerRef .Kind ,
289
+ }
290
+
291
+ mapping , err := dc .mapper .RESTMapping (gk , gv .Version )
292
+ if err != nil {
293
+ return nil , err
294
+ }
295
+ gr := mapping .Resource .GroupResource ()
296
+
297
+ scale , err := dc .scaleNamespacer .Scales (namespace ).Get (gr , controllerRef .Name )
298
+ if err != nil {
299
+ if errors .IsNotFound (err ) {
300
+ return nil , nil
301
+ }
302
+ return nil , err
303
+ }
304
+ if scale .UID != controllerRef .UID {
305
+ return nil , nil
306
+ }
307
+ return & controllerAndScale {scale .UID , scale .Spec .Replicas }, nil
308
+ }
309
+
310
+ func verifyGroupKind (controllerRef * metav1.OwnerReference , expectedKind string , expectedGroups []string ) (bool , error ) {
311
+ gv , err := schema .ParseGroupVersion (controllerRef .APIVersion )
312
+ if err != nil {
313
+ return false , err
314
+ }
315
+
316
+ if controllerRef .Kind != expectedKind {
317
+ return false , nil
318
+ }
319
+
320
+ for _ , group := range expectedGroups {
321
+ if group == gv .Group {
322
+ return true , nil
323
+ }
324
+ }
325
+
326
+ return false , nil
327
+ }
328
+
282
329
func (dc * DisruptionController ) Run (stopCh <- chan struct {}) {
283
330
defer utilruntime .HandleCrash ()
284
331
defer dc .queue .ShutDown ()
@@ -583,10 +630,23 @@ func (dc *DisruptionController) getExpectedScale(pdb *policy.PodDisruptionBudget
583
630
// 1. Find the controller for each pod. If any pod has 0 controllers,
584
631
// that's an error. With ControllerRef, a pod can only have 1 controller.
585
632
for _ , pod := range pods {
633
+ controllerRef := metav1 .GetControllerOf (pod )
634
+ if controllerRef == nil {
635
+ err = fmt .Errorf ("found no controller ref for pod %q" , pod .Name )
636
+ dc .recorder .Event (pdb , v1 .EventTypeWarning , "NoControllerRef" , err .Error ())
637
+ return
638
+ }
639
+
640
+ // If we already know the scale of the controller there is no need to do anything.
641
+ if _ , found := controllerScale [controllerRef .UID ]; found {
642
+ continue
643
+ }
644
+
645
+ // Check all the supported controllers to find the desired scale.
586
646
foundController := false
587
647
for _ , finder := range dc .finders () {
588
648
var controllerNScale * controllerAndScale
589
- controllerNScale , err = finder (pod )
649
+ controllerNScale , err = finder (controllerRef , pod . Namespace )
590
650
if err != nil {
591
651
return
592
652
}
0 commit comments