diff --git a/pkg/controller/controller_utils.go b/pkg/controller/controller_utils.go index d7ba7f8541f..5d24e25dc6e 100644 --- a/pkg/controller/controller_utils.go +++ b/pkg/controller/controller_utils.go @@ -63,6 +63,7 @@ var expKeyFunc = func(obj interface{}) (string, error) { type RCExpectationsManager interface { GetExpectations(rc *api.ReplicationController) (*PodExpectations, bool, error) SatisfiedExpectations(rc *api.ReplicationController) bool + DeleteExpectations(rcKey string) ExpectCreations(rc *api.ReplicationController, adds int) error ExpectDeletions(rc *api.ReplicationController, dels int) error CreationObserved(rc *api.ReplicationController) @@ -87,6 +88,15 @@ func (r *RCExpectations) GetExpectations(rc *api.ReplicationController) (*PodExp } } +// DeleteExpectations deletes the expectations of the given RC from the TTLStore. +func (r *RCExpectations) DeleteExpectations(rcKey string) { + if podExp, exists, err := r.GetByKey(rcKey); err == nil && exists { + if err := r.Delete(podExp); err != nil { + glog.V(2).Infof("Error deleting expectations for rc %v: %v", rcKey, err) + } + } +} + // SatisfiedExpectations returns true if the replication manager has observed the required adds/dels // for the given rc. Add/del counts are established by the rc at sync time, and updated as pods // are observed by the replication manager's podController. diff --git a/pkg/controller/replication_controller.go b/pkg/controller/replication_controller.go index e1866b05f54..395d2df6264 100644 --- a/pkg/controller/replication_controller.go +++ b/pkg/controller/replication_controller.go @@ -354,6 +354,7 @@ func (rm *ReplicationManager) syncReplicationController(key string) error { obj, exists, err := rm.controllerStore.Store.GetByKey(key) if !exists { glog.Infof("Replication Controller has been deleted %v", key) + rm.expectations.DeleteExpectations(key) return nil } if err != nil { diff --git a/pkg/controller/replication_controller_test.go b/pkg/controller/replication_controller_test.go index 2623d36faa2..71ec28e6974 100644 --- a/pkg/controller/replication_controller_test.go +++ b/pkg/controller/replication_controller_test.go @@ -990,3 +990,38 @@ func TestRCSyncExpectations(t *testing.T) { manager.syncReplicationController(getKey(controllerSpec, t)) validateSyncReplication(t, &fakePodControl, 0, 0) } + +func TestDeleteControllerAndExpectations(t *testing.T) { + client := client.NewOrDie(&client.Config{Host: "", Version: testapi.Version()}) + manager := NewReplicationManager(client, 10) + + rc := newReplicationController(1) + manager.controllerStore.Store.Add(rc) + + fakePodControl := FakePodControl{} + manager.podControl = &fakePodControl + + // This should set expectations for the rc + manager.syncReplicationController(getKey(rc, t)) + validateSyncReplication(t, &fakePodControl, 1, 0) + fakePodControl.clear() + + // This is to simulate a concurrent addPod, that has a handle on the expectations + // as the controller deletes it. + podExp, exists, err := manager.expectations.GetExpectations(rc) + if !exists || err != nil { + t.Errorf("No expectations found for rc") + } + manager.controllerStore.Delete(rc) + manager.syncReplicationController(getKey(rc, t)) + + if _, exists, err = manager.expectations.GetExpectations(rc); exists { + t.Errorf("Found expectaions, expected none since the rc has been deleted.") + } + + // This should have no effect, since we've deleted the rc. + podExp.Seen(1, 0) + manager.podStore.Store.Replace(make([]interface{}, 0)) + manager.syncReplicationController(getKey(rc, t)) + validateSyncReplication(t, &fakePodControl, 0, 0) +}