Commit ea85a201 authored by Anthony Yeh's avatar Anthony Yeh

StatefulSet: Use ControllerRef to route watch events.

parent e4f67c81
...@@ -33,7 +33,6 @@ go_library( ...@@ -33,7 +33,6 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/labels", "//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/errors", "//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apimachinery/pkg/util/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apimachinery/pkg/util/wait",
......
...@@ -19,7 +19,6 @@ package statefulset ...@@ -19,7 +19,6 @@ package statefulset
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"sort"
"time" "time"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -50,6 +49,9 @@ const ( ...@@ -50,6 +49,9 @@ const (
statefulSetResyncPeriod = 30 * time.Second statefulSetResyncPeriod = 30 * time.Second
) )
// controllerKind contains the schema.GroupVersionKind for this controller type.
var controllerKind = apps.SchemeGroupVersion.WithKind("StatefulSet")
// StatefulSetController controls statefulsets. // StatefulSetController controls statefulsets.
type StatefulSetController struct { type StatefulSetController struct {
// client interface // client interface
...@@ -158,15 +160,36 @@ func (ssc *StatefulSetController) Run(workers int, stopCh <-chan struct{}) { ...@@ -158,15 +160,36 @@ func (ssc *StatefulSetController) Run(workers int, stopCh <-chan struct{}) {
func (ssc *StatefulSetController) addPod(obj interface{}) { func (ssc *StatefulSetController) addPod(obj interface{}) {
pod := obj.(*v1.Pod) pod := obj.(*v1.Pod)
glog.V(4).Infof("Pod %s created, labels: %+v", pod.Name, pod.Labels) glog.V(4).Infof("Pod %s created, labels: %+v", pod.Name, pod.Labels)
set := ssc.getStatefulSetForPod(pod)
if set == nil { if pod.DeletionTimestamp != nil {
// on a restart of the controller manager, it's possible a new pod shows up in a state that
// is already pending deletion. Prevent the pod from being a creation observation.
ssc.deletePod(pod)
return return
} }
ssc.enqueueStatefulSet(set)
// If it has a ControllerRef, that's all that matters.
if controllerRef := controller.GetControllerOf(pod); controllerRef != nil {
if controllerRef.Kind != controllerKind.Kind {
// It's controlled by a different type of controller.
return
}
set, err := ssc.setLister.StatefulSets(pod.Namespace).Get(controllerRef.Name)
if err != nil {
return
}
ssc.enqueueStatefulSet(set)
return
}
// Otherwise, it's an orphan. Get a list of all matching controllers and sync
// them to see if anyone wants to adopt it.
for _, set := range ssc.getStatefulSetsForPod(pod) {
ssc.enqueueStatefulSet(set)
}
} }
// updatePod adds the statefulset for the current and old pods to the sync queue. // updatePod adds the statefulset for the current and old pods to the sync queue.
// If the labels of the pod didn't change, this method enqueues a single statefulset.
func (ssc *StatefulSetController) updatePod(old, cur interface{}) { func (ssc *StatefulSetController) updatePod(old, cur interface{}) {
curPod := cur.(*v1.Pod) curPod := cur.(*v1.Pod)
oldPod := old.(*v1.Pod) oldPod := old.(*v1.Pod)
...@@ -175,15 +198,41 @@ func (ssc *StatefulSetController) updatePod(old, cur interface{}) { ...@@ -175,15 +198,41 @@ func (ssc *StatefulSetController) updatePod(old, cur interface{}) {
// Two different versions of the same pod will always have different RVs. // Two different versions of the same pod will always have different RVs.
return return
} }
set := ssc.getStatefulSetForPod(curPod) glog.V(4).Infof("Pod %s updated, objectMeta %+v -> %+v.", curPod.Name, oldPod.ObjectMeta, curPod.ObjectMeta)
if set == nil {
labelChanged := !reflect.DeepEqual(curPod.Labels, oldPod.Labels)
curControllerRef := controller.GetControllerOf(curPod)
oldControllerRef := controller.GetControllerOf(oldPod)
controllerRefChanged := !reflect.DeepEqual(curControllerRef, oldControllerRef)
if controllerRefChanged &&
oldControllerRef != nil && oldControllerRef.Kind == controllerKind.Kind {
// The ControllerRef was changed. Sync the old controller, if any.
set, err := ssc.setLister.StatefulSets(oldPod.Namespace).Get(oldControllerRef.Name)
if err == nil {
ssc.enqueueStatefulSet(set)
}
}
// If it has a ControllerRef, that's all that matters.
if curControllerRef != nil {
if curControllerRef.Kind != controllerKind.Kind {
// It's controlled by a different type of controller.
return
}
set, err := ssc.setLister.StatefulSets(curPod.Namespace).Get(curControllerRef.Name)
if err != nil {
return
}
ssc.enqueueStatefulSet(set)
return return
} }
ssc.enqueueStatefulSet(set)
// TODO will we need this going forward with controller ref impl? // Otherwise, it's an orphan. If anything changed, sync matching controllers
if !reflect.DeepEqual(curPod.Labels, oldPod.Labels) { // to see if anyone wants to adopt it now.
if oldSet := ssc.getStatefulSetForPod(oldPod); oldSet != nil { if labelChanged || controllerRefChanged {
ssc.enqueueStatefulSet(oldSet) for _, set := range ssc.getStatefulSetsForPod(curPod) {
ssc.enqueueStatefulSet(set)
} }
} }
} }
...@@ -209,9 +258,22 @@ func (ssc *StatefulSetController) deletePod(obj interface{}) { ...@@ -209,9 +258,22 @@ func (ssc *StatefulSetController) deletePod(obj interface{}) {
} }
} }
glog.V(4).Infof("Pod %s/%s deleted through %v.", pod.Namespace, pod.Name, utilruntime.GetCaller()) glog.V(4).Infof("Pod %s/%s deleted through %v.", pod.Namespace, pod.Name, utilruntime.GetCaller())
if set := ssc.getStatefulSetForPod(pod); set != nil {
ssc.enqueueStatefulSet(set) controllerRef := controller.GetControllerOf(pod)
if controllerRef == nil {
// No controller should care about orphans being deleted.
return
}
if controllerRef.Kind != controllerKind.Kind {
// It's controlled by a different type of controller.
return
} }
set, err := ssc.setLister.StatefulSets(pod.Namespace).Get(controllerRef.Name)
if err != nil {
return
}
ssc.enqueueStatefulSet(set)
} }
// getPodsForStatefulSet returns the Pods that a given StatefulSet should manage. // getPodsForStatefulSet returns the Pods that a given StatefulSet should manage.
...@@ -232,12 +294,13 @@ func (ssc *StatefulSetController) getPodsForStatefulSet(set *apps.StatefulSet, s ...@@ -232,12 +294,13 @@ func (ssc *StatefulSetController) getPodsForStatefulSet(set *apps.StatefulSet, s
return isMemberOf(set, pod) return isMemberOf(set, pod)
} }
cm := controller.NewPodControllerRefManager(ssc.podControl, set, selector, getSSKind()) cm := controller.NewPodControllerRefManager(ssc.podControl, set, selector, controllerKind)
return cm.ClaimPods(pods, filter) return cm.ClaimPods(pods, filter)
} }
// getStatefulSetForPod returns the StatefulSet managing the given pod. // getStatefulSetsForPod returns a list of StatefulSets that potentially match
func (ssc *StatefulSetController) getStatefulSetForPod(pod *v1.Pod) *apps.StatefulSet { // a given pod.
func (ssc *StatefulSetController) getStatefulSetsForPod(pod *v1.Pod) []*apps.StatefulSet {
sets, err := ssc.setLister.GetPodStatefulSets(pod) sets, err := ssc.setLister.GetPodStatefulSets(pod)
if err != nil { if err != nil {
glog.V(4).Infof("No StatefulSets found for pod %v, StatefulSet controller will avoid syncing", pod.Name) glog.V(4).Infof("No StatefulSets found for pod %v, StatefulSet controller will avoid syncing", pod.Name)
...@@ -245,24 +308,14 @@ func (ssc *StatefulSetController) getStatefulSetForPod(pod *v1.Pod) *apps.Statef ...@@ -245,24 +308,14 @@ func (ssc *StatefulSetController) getStatefulSetForPod(pod *v1.Pod) *apps.Statef
} }
// More than one set is selecting the same Pod // More than one set is selecting the same Pod
if len(sets) > 1 { if len(sets) > 1 {
// ControllerRef will ensure we don't do anything crazy, but more than one
// item in this list nevertheless constitutes user error.
utilruntime.HandleError( utilruntime.HandleError(
fmt.Errorf( fmt.Errorf(
"user error: more than one StatefulSet is selecting pods with labels: %+v", "user error: more than one StatefulSet is selecting pods with labels: %+v",
pod.Labels)) pod.Labels))
// The timestamp sort should not be necessary because we will enforce the CreatedBy requirement by
// name
sort.Sort(overlappingStatefulSets(sets))
// return the first created set for which pod is a member
for i := range sets {
if isMemberOf(sets[i], pod) {
return sets[i]
}
}
glog.V(4).Infof("No StatefulSets found for pod %v, StatefulSet controller will avoid syncing", pod.Name)
return nil
} }
return sets[0] return sets
} }
// enqueueStatefulSet enqueues the given statefulset in the work queue. // enqueueStatefulSet enqueues the given statefulset in the work queue.
......
...@@ -22,7 +22,6 @@ import ( ...@@ -22,7 +22,6 @@ import (
"strconv" "strconv"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
podapi "k8s.io/kubernetes/pkg/api/v1/pod" podapi "k8s.io/kubernetes/pkg/api/v1/pod"
apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1" apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
...@@ -232,16 +231,12 @@ func isHealthy(pod *v1.Pod) bool { ...@@ -232,16 +231,12 @@ func isHealthy(pod *v1.Pod) bool {
return isRunningAndReady(pod) && !isTerminated(pod) return isRunningAndReady(pod) && !isTerminated(pod)
} }
func getSSKind() schema.GroupVersionKind {
return apps.SchemeGroupVersion.WithKind("StatefulSet")
}
// newControllerRef returns an ControllerRef pointing to a given StatefulSet. // newControllerRef returns an ControllerRef pointing to a given StatefulSet.
func newControllerRef(set *apps.StatefulSet) *metav1.OwnerReference { func newControllerRef(set *apps.StatefulSet) *metav1.OwnerReference {
isController := true isController := true
return &metav1.OwnerReference{ return &metav1.OwnerReference{
APIVersion: apps.SchemeGroupVersion.String(), APIVersion: controllerKind.GroupVersion().String(),
Kind: "StatefulSet", Kind: controllerKind.Kind,
Name: set.Name, Name: set.Name,
UID: set.UID, UID: set.UID,
Controller: &isController, Controller: &isController,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment