Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1508ecf

Browse files
committed
Make PDBs represent percentage in StatefulSet
1 parent d12d012 commit 1508ecf

2 files changed

Lines changed: 108 additions & 3 deletions

File tree

pkg/controller/disruption/disruption.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"k8s.io/kubernetes/pkg/api"
2525
"k8s.io/kubernetes/pkg/api/v1"
26+
apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
2627
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
2728
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
2829
policy "k8s.io/kubernetes/pkg/apis/policy/v1beta1"
@@ -51,7 +52,7 @@ const statusUpdateRetries = 2
5152
// all and the corresponding entry can be removed from pdb.Status.DisruptedPods. It is assumed that
5253
// pod/pdb apiserver to controller latency is relatively small (like 1-2sec) so the below value should
5354
// be more than enough.
54-
// If the cotroller is running on a different node it is important that the two nodes have synced
55+
// If the controller is running on a different node it is important that the two nodes have synced
5556
// clock (via ntp for example). Otherwise PodDisruptionBudget controller may not provide enough
5657
// protection against unwanted pod disruptions.
5758
const DeletionTimeout = 2 * 60 * time.Second
@@ -80,6 +81,10 @@ type DisruptionController struct {
8081
dController *cache.Controller
8182
dLister cache.StoreToDeploymentLister
8283

84+
ssStore cache.Store
85+
ssController *cache.Controller
86+
ssLister cache.StoreToStatefulSetLister
87+
8388
// PodDisruptionBudget keys that need to be synced.
8489
queue workqueue.RateLimitingInterface
8590
recheckQueue workqueue.DelayingInterface
@@ -187,9 +192,23 @@ func NewDisruptionController(podInformer cache.SharedIndexInformer, kubeClient c
187192
cache.ResourceEventHandlerFuncs{},
188193
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
189194
)
190-
191195
dc.dLister.Indexer = dc.dIndexer
192196

197+
dc.ssStore, dc.ssController = cache.NewInformer(
198+
&cache.ListWatch{
199+
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
200+
return dc.kubeClient.Apps().StatefulSets(v1.NamespaceAll).List(options)
201+
},
202+
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
203+
return dc.kubeClient.Apps().StatefulSets(v1.NamespaceAll).Watch(options)
204+
},
205+
},
206+
&apps.StatefulSet{},
207+
30*time.Second,
208+
cache.ResourceEventHandlerFuncs{},
209+
)
210+
dc.ssLister.Store = dc.ssStore
211+
193212
return dc
194213
}
195214

@@ -201,7 +220,8 @@ func NewDisruptionController(podInformer cache.SharedIndexInformer, kubeClient c
201220
// and we may well need further tweaks just to be able to access scale
202221
// subresources.
203222
func (dc *DisruptionController) finders() []podControllerFinder {
204-
return []podControllerFinder{dc.getPodReplicationControllers, dc.getPodDeployments, dc.getPodReplicaSets}
223+
return []podControllerFinder{dc.getPodReplicationControllers, dc.getPodDeployments, dc.getPodReplicaSets,
224+
dc.getPodStatefulSets}
205225
}
206226

207227
// getPodReplicaSets finds replicasets which have no matching deployments.
@@ -231,6 +251,29 @@ func (dc *DisruptionController) getPodReplicaSets(pod *v1.Pod) ([]controllerAndS
231251
return cas, nil
232252
}
233253

254+
// getPodStatefulSet returns the statefulset managing the given pod.
255+
func (dc *DisruptionController) getPodStatefulSets(pod *v1.Pod) ([]controllerAndScale, error) {
256+
cas := []controllerAndScale{}
257+
ss, err := dc.ssLister.GetPodStatefulSets(pod)
258+
259+
// GetPodStatefulSets returns an error only if no StatefulSets are found. We
260+
// don't return that as an error to the caller.
261+
if err != nil {
262+
return cas, nil
263+
}
264+
265+
controllerScale := map[types.UID]int32{}
266+
for _, s := range ss {
267+
controllerScale[s.UID] = *(s.Spec.Replicas)
268+
}
269+
270+
for uid, scale := range controllerScale {
271+
cas = append(cas, controllerAndScale{UID: uid, scale: scale})
272+
}
273+
274+
return cas, nil
275+
}
276+
234277
// getPodDeployments finds deployments for any replicasets which are being managed by deployments.
235278
func (dc *DisruptionController) getPodDeployments(pod *v1.Pod) ([]controllerAndScale, error) {
236279
cas := []controllerAndScale{}
@@ -284,6 +327,7 @@ func (dc *DisruptionController) Run(stopCh <-chan struct{}) {
284327
go dc.rcController.Run(stopCh)
285328
go dc.rsController.Run(stopCh)
286329
go dc.dController.Run(stopCh)
330+
go dc.ssController.Run(stopCh)
287331
go wait.Until(dc.worker, time.Second, stopCh)
288332
go wait.Until(dc.recheckWorker, time.Second, stopCh)
289333

pkg/controller/disruption/disruption_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"k8s.io/kubernetes/pkg/api"
2727
"k8s.io/kubernetes/pkg/api/v1"
2828
"k8s.io/kubernetes/pkg/apimachinery/registered"
29+
apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
2930
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
3031
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
3132
policy "k8s.io/kubernetes/pkg/apis/policy/v1beta1"
@@ -92,6 +93,7 @@ func newFakeDisruptionController() (*DisruptionController, *pdbStates) {
9293
rcLister: cache.StoreToReplicationControllerLister{Indexer: cache.NewIndexer(controller.KeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})},
9394
rsLister: cache.StoreToReplicaSetLister{Indexer: cache.NewIndexer(controller.KeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})},
9495
dLister: cache.StoreToDeploymentLister{Indexer: cache.NewIndexer(controller.KeyFunc, cache.Indexers{})},
96+
ssLister: cache.StoreToStatefulSetLister{Store: cache.NewStore(controller.KeyFunc)},
9597
getUpdater: func() updater { return ps.Set },
9698
broadcaster: record.NewBroadcaster(),
9799
}
@@ -236,6 +238,30 @@ func newReplicaSet(t *testing.T, size int32) (*extensions.ReplicaSet, string) {
236238
return rs, rsName
237239
}
238240

241+
func newStatefulSet(t *testing.T, size int32) (*apps.StatefulSet, string) {
242+
ss := &apps.StatefulSet{
243+
TypeMeta: metav1.TypeMeta{APIVersion: registered.GroupOrDie(v1.GroupName).GroupVersion.String()},
244+
ObjectMeta: v1.ObjectMeta{
245+
UID: uuid.NewUUID(),
246+
Name: "foobar",
247+
Namespace: v1.NamespaceDefault,
248+
ResourceVersion: "18",
249+
Labels: fooBar(),
250+
},
251+
Spec: apps.StatefulSetSpec{
252+
Replicas: &size,
253+
Selector: newSelFooBar(),
254+
},
255+
}
256+
257+
ssName, err := controller.KeyFunc(ss)
258+
if err != nil {
259+
t.Fatalf("Unexpected error naming StatefulSet %q: %v", ss.Name, err)
260+
}
261+
262+
return ss, ssName
263+
}
264+
239265
func update(t *testing.T, store cache.Store, obj interface{}) {
240266
if err := store.Update(obj); err != nil {
241267
t.Fatalf("Could not add %+v to %+v: %v", obj, store, err)
@@ -409,6 +435,41 @@ func TestReplicationController(t *testing.T) {
409435
ps.VerifyDisruptionAllowed(t, pdbName, 0)
410436
}
411437

438+
func TestStatefulSetController(t *testing.T) {
439+
labels := map[string]string{
440+
"foo": "bar",
441+
"baz": "quux",
442+
}
443+
444+
dc, ps := newFakeDisruptionController()
445+
446+
// 34% should round up to 2
447+
pdb, pdbName := newPodDisruptionBudget(t, intstr.FromString("34%"))
448+
add(t, dc.pdbLister.Store, pdb)
449+
ss, _ := newStatefulSet(t, 3)
450+
add(t, dc.ssLister.Store, ss)
451+
dc.sync(pdbName)
452+
453+
// It starts out at 0 expected because, with no pods, the PDB doesn't know
454+
// about the SS. This is a known bug. TODO(mml): file issue
455+
ps.VerifyPdbStatus(t, pdbName, 0, 0, 0, 0, map[string]metav1.Time{})
456+
457+
pods := []*v1.Pod{}
458+
459+
for i := int32(0); i < 3; i++ {
460+
pod, _ := newPod(t, fmt.Sprintf("foobar %d", i))
461+
pods = append(pods, pod)
462+
pod.Labels = labels
463+
add(t, dc.podLister.Indexer, pod)
464+
dc.sync(pdbName)
465+
if i < 2 {
466+
ps.VerifyPdbStatus(t, pdbName, 0, i+1, 2, 3, map[string]metav1.Time{})
467+
} else {
468+
ps.VerifyPdbStatus(t, pdbName, 1, 3, 2, 3, map[string]metav1.Time{})
469+
}
470+
}
471+
}
472+
412473
func TestTwoControllers(t *testing.T) {
413474
// Most of this test is in verifying intermediate cases as we define the
414475
// three controllers and create the pods.

0 commit comments

Comments
 (0)