Track deletes in rc manager with a UID expectations cache.
This commit is contained in:
@@ -35,6 +35,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
"k8s.io/kubernetes/pkg/util/integer"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -243,11 +244,105 @@ func (e *ControlleeExpectations) GetExpectations() (int64, int64) {
|
||||
return atomic.LoadInt64(&e.add), atomic.LoadInt64(&e.del)
|
||||
}
|
||||
|
||||
// NewControllerExpectations returns a store for ControlleeExpectations.
|
||||
// NewControllerExpectations returns a store for ControllerExpectations.
|
||||
func NewControllerExpectations() *ControllerExpectations {
|
||||
return &ControllerExpectations{cache.NewStore(ExpKeyFunc)}
|
||||
}
|
||||
|
||||
// UIDSetKeyFunc to parse out the key from a UIDSet.
|
||||
var UIDSetKeyFunc = func(obj interface{}) (string, error) {
|
||||
if u, ok := obj.(*UIDSet); ok {
|
||||
return u.key, nil
|
||||
}
|
||||
return "", fmt.Errorf("Could not find key for obj %#v", obj)
|
||||
}
|
||||
|
||||
// UIDSet holds a key and a set of UIDs. Used by the
|
||||
// UIDTrackingControllerExpectations to remember which UID it has seen/still
|
||||
// waiting for.
|
||||
type UIDSet struct {
|
||||
sets.String
|
||||
key string
|
||||
}
|
||||
|
||||
// UIDTrackingControllerExpectations tracks the UID of the pods it deletes.
|
||||
// This cache is needed over plain old expectations to safely handle graceful
|
||||
// deletion. The desired behavior is to treat an update that sets the
|
||||
// DeletionTimestamp on an object as a delete. To do so consistenly, one needs
|
||||
// to remember the expected deletes so they aren't double counted.
|
||||
// TODO: Track creates as well (#22599)
|
||||
type UIDTrackingControllerExpectations struct {
|
||||
ControllerExpectationsInterface
|
||||
// TODO: There is a much nicer way to do this that involves a single store,
|
||||
// a lock per entry, and a ControlleeExpectationsInterface type.
|
||||
uidStoreLock sync.Mutex
|
||||
// Store used for the UIDs associated with any expectation tracked via the
|
||||
// ControllerExpectationsInterface.
|
||||
uidStore cache.Store
|
||||
}
|
||||
|
||||
// GetUIDs is a convenience method to avoid exposing the set of expected uids.
|
||||
// The returned set is not thread safe, all modifications must be made holding
|
||||
// the uidStoreLock.
|
||||
func (u *UIDTrackingControllerExpectations) GetUIDs(controllerKey string) sets.String {
|
||||
if uid, exists, err := u.uidStore.GetByKey(controllerKey); err == nil && exists {
|
||||
return uid.(*UIDSet).String
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExpectDeletions records expectations for the given deleteKeys, against the given controller.
|
||||
func (u *UIDTrackingControllerExpectations) ExpectDeletions(rcKey string, deletedKeys []string) error {
|
||||
u.uidStoreLock.Lock()
|
||||
defer u.uidStoreLock.Unlock()
|
||||
|
||||
if existing := u.GetUIDs(rcKey); existing != nil && existing.Len() != 0 {
|
||||
glog.Errorf("Clobbering existing delete keys: %+v", existing)
|
||||
}
|
||||
expectedUIDs := sets.NewString()
|
||||
for _, k := range deletedKeys {
|
||||
expectedUIDs.Insert(k)
|
||||
}
|
||||
glog.V(4).Infof("Controller %v waiting on deletions for: %+v", rcKey, deletedKeys)
|
||||
if err := u.uidStore.Add(&UIDSet{expectedUIDs, rcKey}); err != nil {
|
||||
return err
|
||||
}
|
||||
return u.ControllerExpectationsInterface.ExpectDeletions(rcKey, expectedUIDs.Len())
|
||||
}
|
||||
|
||||
// DeletionObserved records the given deleteKey as a deletion, for the given rc.
|
||||
func (u *UIDTrackingControllerExpectations) DeletionObserved(rcKey, deleteKey string) {
|
||||
u.uidStoreLock.Lock()
|
||||
defer u.uidStoreLock.Unlock()
|
||||
|
||||
uids := u.GetUIDs(rcKey)
|
||||
if uids != nil && uids.Has(deleteKey) {
|
||||
glog.V(4).Infof("Controller %v received delete for pod %v", rcKey, deleteKey)
|
||||
u.ControllerExpectationsInterface.DeletionObserved(rcKey)
|
||||
uids.Delete(deleteKey)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteExpectations deletes the UID set and invokes DeleteExpectations on the
|
||||
// underlying ControllerExpectationsInterface.
|
||||
func (u *UIDTrackingControllerExpectations) DeleteExpectations(rcKey string) {
|
||||
u.uidStoreLock.Lock()
|
||||
defer u.uidStoreLock.Unlock()
|
||||
|
||||
u.ControllerExpectationsInterface.DeleteExpectations(rcKey)
|
||||
if uidExp, exists, err := u.uidStore.GetByKey(rcKey); err == nil && exists {
|
||||
if err := u.uidStore.Delete(uidExp); err != nil {
|
||||
glog.V(2).Infof("Error deleting uid expectations for controller %v: %v", rcKey, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewUIDTrackingControllerExpectations returns a wrapper around
|
||||
// ControllerExpectations that is aware of deleteKeys.
|
||||
func NewUIDTrackingControllerExpectations(ce ControllerExpectationsInterface) *UIDTrackingControllerExpectations {
|
||||
return &UIDTrackingControllerExpectations{ControllerExpectationsInterface: ce, uidStore: cache.NewStore(UIDSetKeyFunc)}
|
||||
}
|
||||
|
||||
// PodControlInterface is an interface that knows how to add or delete pods
|
||||
// created as an interface to allow testing.
|
||||
type PodControlInterface interface {
|
||||
@@ -517,6 +612,14 @@ func FilterActiveReplicaSets(replicaSets []*extensions.ReplicaSet) []*extensions
|
||||
return active
|
||||
}
|
||||
|
||||
// PodKey returns a key unique to the given pod within a cluster.
|
||||
// It's used so we consistently use the same key scheme in this module.
|
||||
// It does exactly what cache.MetaNamespaceKeyFunc would have done
|
||||
// expcept there's not possibility for error since we know the exact type.
|
||||
func PodKey(pod *api.Pod) string {
|
||||
return fmt.Sprintf("%v/%v", pod.Namespace, pod.Name)
|
||||
}
|
||||
|
||||
// ControllersByCreationTimestamp sorts a list of ReplicationControllers by creation timestamp, using their names as a tie breaker.
|
||||
type ControllersByCreationTimestamp []*api.ReplicationController
|
||||
|
||||
|
Reference in New Issue
Block a user