Skip to content

Commit 4c8af52

Browse files
authored
Merge pull request #16 from aermakov-zalando/use-max-unavailable
Create PDBs with maxUnavailable: 1 instead of minAvailable: 1
2 parents f7f0e93 + 0a440c1 commit 4c8af52

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

controller.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
131131
continue
132132
}
133133

134+
// remove PDBs that are no longer valid, they'll be recreated on the next iteration
135+
for _, pdb := range ownedPDBs {
136+
if !pdbSpecValid(pdb) {
137+
removePDB = append(removePDB, pdb)
138+
}
139+
}
140+
134141
// if nonReadyTTL is enabled and not all replicas of the
135142
// deployment is ready then we check when the pods were last
136143
// ready. This is done to ensure we don't keep PDBs for broken
@@ -178,6 +185,14 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
178185
// owned PDBs to not shadow what's defined by users.
179186
if len(ownedPDBs) != len(matchedPDBs) {
180187
removePDB = append(removePDB, ownedPDBs...)
188+
continue
189+
}
190+
191+
// remove PDBs that are no longer valid, they'll be recreated on the next iteration
192+
for _, pdb := range ownedPDBs {
193+
if !pdbSpecValid(pdb) {
194+
removePDB = append(removePDB, pdb)
195+
}
181196
}
182197

183198
// if nonReadyTTL is enabled and not all replicas of the
@@ -200,10 +215,10 @@ func (n *PDBController) addPDBs(namespace *v1.Namespace) error {
200215

201216
// add missing PDBs
202217
for _, resource := range addPDB {
203-
minAvailable := intstr.FromInt(1)
218+
maxUnavailable := intstr.FromInt(1)
204219
pdb := &pv1beta1.PodDisruptionBudget{
205220
Spec: pv1beta1.PodDisruptionBudgetSpec{
206-
MinAvailable: &minAvailable,
221+
MaxUnavailable: &maxUnavailable,
207222
},
208223
}
209224

@@ -316,6 +331,11 @@ func (n *PDBController) getPodsLastTransitionTime(namespace string, selector map
316331
return lastTransitionTime, nil
317332
}
318333

334+
// pdbSpecValid returns true if the PDB spec is up-to-date
335+
func pdbSpecValid(pdb pv1beta1.PodDisruptionBudget) bool {
336+
return pdb.Spec.MinAvailable == nil
337+
}
338+
319339
// getPDBs gets matching PodDisruptionBudgets.
320340
func getPDBs(labels map[string]string, pdbs []pv1beta1.PodDisruptionBudget, selector map[string]string) []pv1beta1.PodDisruptionBudget {
321341
matchedPDBs := make([]pv1beta1.PodDisruptionBudget, 0)

controller_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package main
33
import (
44
"testing"
55

6+
"k8s.io/apimachinery/pkg/api/errors"
67
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/apimachinery/pkg/util/intstr"
79
"k8s.io/client-go/kubernetes"
810
"k8s.io/client-go/kubernetes/fake"
911
"k8s.io/client-go/pkg/api/v1"
@@ -82,6 +84,107 @@ func TestRun(t *testing.T) {
8284
stopCh <- struct{}{}
8385
}
8486

87+
func TestRemoveInvalidPDBs(t *testing.T) {
88+
deplabels := map[string]string{"foo": "deployment"}
89+
sslabels := map[string]string{"foo": "statefulset"}
90+
replicas := int32(2)
91+
92+
one := intstr.FromInt(1)
93+
pdbs := []*pv1beta1.PodDisruptionBudget{
94+
{
95+
ObjectMeta: metav1.ObjectMeta{
96+
Name: "pdb-1",
97+
Labels: ownerLabels,
98+
},
99+
Spec: pv1beta1.PodDisruptionBudgetSpec{
100+
Selector: &metav1.LabelSelector{
101+
MatchLabels: deplabels,
102+
},
103+
MinAvailable: &one,
104+
},
105+
},
106+
{
107+
ObjectMeta: metav1.ObjectMeta{
108+
Name: "pdb-2",
109+
Labels: ownerLabels,
110+
},
111+
Spec: pv1beta1.PodDisruptionBudgetSpec{
112+
Selector: &metav1.LabelSelector{
113+
MatchLabels: sslabels,
114+
},
115+
MinAvailable: &one,
116+
},
117+
},
118+
}
119+
120+
deployments := []*v1beta1.Deployment{
121+
{
122+
ObjectMeta: metav1.ObjectMeta{
123+
Name: "deployment-1",
124+
Labels: deplabels,
125+
},
126+
Spec: v1beta1.DeploymentSpec{
127+
Replicas: &replicas,
128+
Selector: &metav1.LabelSelector{
129+
MatchLabels: deplabels,
130+
},
131+
Template: v1.PodTemplateSpec{
132+
ObjectMeta: metav1.ObjectMeta{
133+
Labels: deplabels,
134+
},
135+
},
136+
},
137+
},
138+
}
139+
140+
statefulSets := []*v1beta1.StatefulSet{
141+
{
142+
ObjectMeta: metav1.ObjectMeta{
143+
Name: "stateful-set-1",
144+
Labels: sslabels,
145+
},
146+
Spec: v1beta1.StatefulSetSpec{
147+
Replicas: &replicas,
148+
Selector: &metav1.LabelSelector{
149+
MatchLabels: sslabels,
150+
},
151+
Template: v1.PodTemplateSpec{
152+
ObjectMeta: metav1.ObjectMeta{
153+
Labels: sslabels,
154+
},
155+
},
156+
},
157+
},
158+
}
159+
160+
namespaces := []*v1.Namespace{
161+
{
162+
ObjectMeta: metav1.ObjectMeta{
163+
Name: "default",
164+
},
165+
},
166+
}
167+
168+
controller := &PDBController{
169+
Interface: setupMockKubernetes(t, pdbs, deployments, statefulSets, namespaces),
170+
}
171+
172+
err := controller.addPDBs(namespaces[0])
173+
if err != nil {
174+
t.Error(err)
175+
}
176+
177+
for _, pdb := range []string{"pdb-1", "pdb-2"} {
178+
pdbResource, err := controller.Interface.PolicyV1beta1().PodDisruptionBudgets("default").Get(pdb, metav1.GetOptions{})
179+
if err == nil {
180+
t.Fatalf("unexpected pdb (%s) found: %v", pdb, pdbResource)
181+
}
182+
if !errors.IsNotFound(err) {
183+
t.Fatalf("unexpected error: %s", err)
184+
}
185+
}
186+
}
187+
85188
func TestAddPDBs(t *testing.T) {
86189
labels := map[string]string{"foo": "bar"}
87190
notFoundLabels := map[string]string{"bar": "foo"}

0 commit comments

Comments
 (0)