@@ -2,21 +2,25 @@ package main
2
2
3
3
import (
4
4
"fmt"
5
+ "reflect"
5
6
"time"
6
7
7
8
log "github.com/sirupsen/logrus"
8
9
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9
10
"k8s.io/apimachinery/pkg/labels"
10
11
"k8s.io/apimachinery/pkg/util/intstr"
11
12
"k8s.io/client-go/kubernetes"
12
- "k8s.io/client-go/pkg/api/v1"
13
+ v1 "k8s.io/client-go/pkg/api/v1"
13
14
"k8s.io/client-go/pkg/apis/apps/v1beta1"
14
15
pv1beta1 "k8s.io/client-go/pkg/apis/policy/v1beta1"
15
16
)
16
17
17
18
const (
18
19
heritageLabel = "heritage"
19
20
pdbController = "pdb-controller"
21
+
22
+ deploymentOwnershipLabel = "pod-template-hash"
23
+ statefulsetOwnershipLabel = "statefulset.kubernetes.io/pod-name"
20
24
)
21
25
22
26
var (
@@ -99,7 +103,7 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
99
103
return err
100
104
}
101
105
102
- addPDB := make ([]interface {} , 0 , len (deployments .Items )+ len (statefulSets .Items ))
106
+ addPDB := make ([]metav1. Object , 0 , len (deployments .Items )+ len (statefulSets .Items ))
103
107
removePDB := make ([]pv1beta1.PodDisruptionBudget , 0 , len (deployments .Items )+ len (statefulSets .Items ))
104
108
105
109
nonReadTTL := time .Now ().UTC ().Add (- n .nonReadyTTL )
@@ -111,7 +115,8 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
111
115
// ready, add one
112
116
if deployment .Status .ReadyReplicas == * deployment .Spec .Replicas {
113
117
if len (matchedPDBs ) == 0 && * deployment .Spec .Replicas > 1 {
114
- addPDB = append (addPDB , deployment )
118
+ obj := & deployment
119
+ addPDB = append (addPDB , obj )
115
120
}
116
121
}
117
122
@@ -168,7 +173,8 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
168
173
// ready, add one
169
174
if statefulSet .Status .ReadyReplicas == * statefulSet .Spec .Replicas {
170
175
if len (matchedPDBs ) == 0 && * statefulSet .Spec .Replicas > 1 {
171
- addPDB = append (addPDB , statefulSet )
176
+ obj := & statefulSet
177
+ addPDB = append (addPDB , obj )
172
178
}
173
179
}
174
180
@@ -215,50 +221,15 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
215
221
216
222
// add missing PDBs
217
223
for _ , resource := range addPDB {
218
- maxUnavailable := intstr .FromInt (1 )
219
- pdb := & pv1beta1.PodDisruptionBudget {
220
- Spec : pv1beta1.PodDisruptionBudgetSpec {
221
- MaxUnavailable : & maxUnavailable ,
222
- },
223
- }
224
+ var pdb * pv1beta1.PodDisruptionBudget
224
225
225
226
switch r := resource .(type ) {
226
- case v1beta1.Deployment :
227
- if r .Labels == nil {
228
- r .Labels = make (map [string ]string )
229
- }
230
- labels := r .Labels
231
- labels [heritageLabel ] = pdbController
232
- pdb .Name = r .Name
233
- pdb .Namespace = r .Namespace
234
- pdb .OwnerReferences = []metav1.OwnerReference {
235
- {
236
- APIVersion : "apps/v1" ,
237
- Kind : "Deployment" ,
238
- Name : r .Name ,
239
- UID : r .UID ,
240
- },
241
- }
242
- pdb .Labels = labels
243
- pdb .Spec .Selector = r .Spec .Selector
244
- case v1beta1.StatefulSet :
245
- if r .Labels == nil {
246
- r .Labels = make (map [string ]string )
247
- }
248
- labels := r .Labels
249
- labels [heritageLabel ] = pdbController
250
- pdb .Name = r .Name
251
- pdb .Namespace = r .Namespace
252
- pdb .OwnerReferences = []metav1.OwnerReference {
253
- {
254
- APIVersion : "apps/v1" ,
255
- Kind : "StatefulSet" ,
256
- Name : r .Name ,
257
- UID : r .UID ,
258
- },
259
- }
260
- pdb .Labels = labels
261
- pdb .Spec .Selector = r .Spec .Selector
227
+ case * v1beta1.Deployment :
228
+ pdb = generatePDB (r .APIVersion , r .Kind , r , r .Spec .Selector , deploymentOwnershipLabel )
229
+ case * v1beta1.StatefulSet :
230
+ pdb = generatePDB (r .APIVersion , r .Kind , r , r .Spec .Selector , statefulsetOwnershipLabel )
231
+ default :
232
+ return fmt .Errorf ("unknown type for %s/%s: %s" , resource .GetNamespace (), resource .GetName (), reflect .TypeOf (r ))
262
233
}
263
234
264
235
if n .pdbNameSuffix != "" {
@@ -298,6 +269,41 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
298
269
return nil
299
270
}
300
271
272
+ func generatePDB (apiVersion , kind string , object metav1.Object , selector * metav1.LabelSelector , ownershipLabel string ) * pv1beta1.PodDisruptionBudget {
273
+ maxUnavailable := intstr .FromInt (1 )
274
+ pdb := & pv1beta1.PodDisruptionBudget {
275
+ Spec : pv1beta1.PodDisruptionBudgetSpec {
276
+ MaxUnavailable : & maxUnavailable ,
277
+ },
278
+ }
279
+
280
+ pdb .Labels = object .GetLabels ()
281
+ if pdb .Labels == nil {
282
+ pdb .Labels = make (map [string ]string )
283
+ }
284
+ pdb .Labels [heritageLabel ] = pdbController
285
+
286
+ pdb .Name = object .GetName ()
287
+ pdb .Namespace = object .GetNamespace ()
288
+ pdb .OwnerReferences = []metav1.OwnerReference {
289
+ {
290
+ APIVersion : apiVersion ,
291
+ Kind : kind ,
292
+ Name : object .GetName (),
293
+ UID : object .GetUID (),
294
+ },
295
+ }
296
+ pdb .Spec .Selector = selector
297
+ if ! hasOwnershipMatchExpression (pdb .Spec .Selector ) {
298
+ pdb .Spec .Selector .MatchExpressions = append (pdb .Spec .Selector .MatchExpressions , metav1.LabelSelectorRequirement {
299
+ Key : ownershipLabel ,
300
+ Operator : metav1 .LabelSelectorOpExists ,
301
+ })
302
+ }
303
+
304
+ return pdb
305
+ }
306
+
301
307
// getPodsLastTransitionTime returns the latest transition time for the pod not
302
308
// ready condition of all pods matched by the selector.
303
309
func (n * PDBController ) getPodsLastTransitionTime (namespace string , selector map [string ]string ) (time.Time , error ) {
@@ -331,9 +337,21 @@ func (n *PDBController) getPodsLastTransitionTime(namespace string, selector map
331
337
return lastTransitionTime , nil
332
338
}
333
339
340
+ func hasOwnershipMatchExpression (selector * metav1.LabelSelector ) bool {
341
+ for _ , expr := range selector .MatchExpressions {
342
+ if expr .Operator == metav1 .LabelSelectorOpExists {
343
+ switch expr .Key {
344
+ case deploymentOwnershipLabel , statefulsetOwnershipLabel :
345
+ return true
346
+ }
347
+ }
348
+ }
349
+ return false
350
+ }
351
+
334
352
// pdbSpecValid returns true if the PDB spec is up-to-date
335
353
func pdbSpecValid (pdb pv1beta1.PodDisruptionBudget ) bool {
336
- return pdb .Spec .MinAvailable == nil
354
+ return pdb .Spec .MinAvailable == nil && hasOwnershipMatchExpression ( pdb . Spec . Selector )
337
355
}
338
356
339
357
// getPDBs gets matching PodDisruptionBudgets.
0 commit comments