From 5a99edaeb08df78ccd7d008d7ea03d7d3e741e56 Mon Sep 17 00:00:00 2001 From: Bo Ingram Date: Sun, 4 Jun 2017 20:04:13 -0600 Subject: [PATCH] deletePod handler in the deployment controller shouldn't set owner refs --- .../deployment/deployment_controller.go | 2 +- .../deployment/deployment_controller_test.go | 76 ++++++++++++++++++- .../deployment/util/deployment_util.go | 14 ++-- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/pkg/controller/deployment/deployment_controller.go b/pkg/controller/deployment/deployment_controller.go index f5963acba3d..9becf2255b6 100644 --- a/pkg/controller/deployment/deployment_controller.go +++ b/pkg/controller/deployment/deployment_controller.go @@ -356,7 +356,7 @@ func (dc *DeploymentController) deletePod(obj interface{}) { glog.V(4).Infof("Pod %s deleted.", pod.Name) if d := dc.getDeploymentForPod(pod); d != nil && d.Spec.Strategy.Type == extensions.RecreateDeploymentStrategyType { // Sync if this Deployment now has no more Pods. - rsList, err := dc.getReplicaSetsForDeployment(d) + rsList, err := util.ListReplicaSets(d, util.RsListFromClient(dc.client)) if err != nil { return } diff --git a/pkg/controller/deployment/deployment_controller_test.go b/pkg/controller/deployment/deployment_controller_test.go index a1544c5e82f..53b606007ce 100644 --- a/pkg/controller/deployment/deployment_controller_test.go +++ b/pkg/controller/deployment/deployment_controller_test.go @@ -415,11 +415,81 @@ func TestPodDeletionDoesntEnqueueRecreateDeployment(t *testing.T) { foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"}) foo.Spec.Strategy.Type = extensions.RecreateDeploymentStrategyType - rs := newReplicaSet(foo, "foo-1", 1) - pod := generatePodFromRS(rs) + rs1 := newReplicaSet(foo, "foo-1", 1) + rs2 := newReplicaSet(foo, "foo-1", 1) + pod1 := generatePodFromRS(rs1) + pod2 := generatePodFromRS(rs2) f.dLister = append(f.dLister, foo) - f.rsLister = append(f.rsLister, rs) + // Let's pretend this is a different pod. The gist is that the pod lister needs to + // return a non-empty list. + f.podLister = append(f.podLister, pod1, pod2) + + c, _ := f.newController() + enqueued := false + c.enqueueDeployment = func(d *extensions.Deployment) { + if d.Name == "foo" { + enqueued = true + } + } + + c.deletePod(pod1) + + if enqueued { + t.Errorf("expected deployment %q not to be queued after pod deletion", foo.Name) + } +} + +// TestPodDeletionPartialReplicaSetOwnershipEnqueueRecreateDeployment ensures that +// the deletion of a pod will requeue a Recreate deployment iff there is no other +// pod returned from the client in the case where a deployment has multiple replica +// sets, some of which have empty owner references. +func TestPodDeletionPartialReplicaSetOwnershipEnqueueRecreateDeployment(t *testing.T) { + f := newFixture(t) + + foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"}) + foo.Spec.Strategy.Type = extensions.RecreateDeploymentStrategyType + rs1 := newReplicaSet(foo, "foo-1", 1) + rs2 := newReplicaSet(foo, "foo-2", 2) + rs2.OwnerReferences = nil + pod := generatePodFromRS(rs1) + + f.dLister = append(f.dLister, foo) + f.rsLister = append(f.rsLister, rs1, rs2) + f.objects = append(f.objects, foo, rs1, rs2) + + c, _ := f.newController() + enqueued := false + c.enqueueDeployment = func(d *extensions.Deployment) { + if d.Name == "foo" { + enqueued = true + } + } + + c.deletePod(pod) + + if !enqueued { + t.Errorf("expected deployment %q to be queued after pod deletion", foo.Name) + } +} + +// TestPodDeletionPartialReplicaSetOwnershipDoesntEnqueueRecreateDeployment that the +// deletion of a pod will not requeue a Recreate deployment iff there are other pods +// returned from the client in the case where a deployment has multiple replica sets, +// some of which have empty owner references. +func TestPodDeletionPartialReplicaSetOwnershipDoesntEnqueueRecreateDeployment(t *testing.T) { + f := newFixture(t) + + foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"}) + foo.Spec.Strategy.Type = extensions.RecreateDeploymentStrategyType + rs1 := newReplicaSet(foo, "foo-1", 1) + rs2 := newReplicaSet(foo, "foo-2", 2) + rs2.OwnerReferences = nil + pod := generatePodFromRS(rs1) + + f.dLister = append(f.dLister, foo) + f.rsLister = append(f.rsLister, rs1, rs2) + f.objects = append(f.objects, foo, rs1, rs2) // Let's pretend this is a different pod. The gist is that the pod lister needs to // return a non-empty list. f.podLister = append(f.podLister, pod) diff --git a/pkg/controller/deployment/util/deployment_util.go b/pkg/controller/deployment/util/deployment_util.go index ea6ff569a99..b80094388a2 100644 --- a/pkg/controller/deployment/util/deployment_util.go +++ b/pkg/controller/deployment/util/deployment_util.go @@ -489,7 +489,7 @@ func getReplicaSetFraction(rs extensions.ReplicaSet, d extensions.Deployment) in // Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets. // The third returned value is the new replica set, and it may be nil if it doesn't exist yet. func GetAllReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, *extensions.ReplicaSet, error) { - rsList, err := ListReplicaSets(deployment, rsListFromClient(c)) + rsList, err := ListReplicaSets(deployment, RsListFromClient(c)) if err != nil { return nil, nil, nil, err } @@ -507,7 +507,7 @@ func GetAllReplicaSets(deployment *extensions.Deployment, c clientset.Interface) // GetOldReplicaSets returns the old replica sets targeted by the given Deployment; get PodList and ReplicaSetList from client interface. // Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets. func GetOldReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, error) { - rsList, err := ListReplicaSets(deployment, rsListFromClient(c)) + rsList, err := ListReplicaSets(deployment, RsListFromClient(c)) if err != nil { return nil, nil, err } @@ -517,15 +517,15 @@ func GetOldReplicaSets(deployment *extensions.Deployment, c clientset.Interface) // GetNewReplicaSet returns a replica set that matches the intent of the given deployment; get ReplicaSetList from client interface. // Returns nil if the new replica set doesn't exist yet. func GetNewReplicaSet(deployment *extensions.Deployment, c clientset.Interface) (*extensions.ReplicaSet, error) { - rsList, err := ListReplicaSets(deployment, rsListFromClient(c)) + rsList, err := ListReplicaSets(deployment, RsListFromClient(c)) if err != nil { return nil, err } return FindNewReplicaSet(deployment, rsList) } -// rsListFromClient returns an rsListFunc that wraps the given client. -func rsListFromClient(c clientset.Interface) rsListFunc { +// RsListFromClient returns an rsListFunc that wraps the given client. +func RsListFromClient(c clientset.Interface) RsListFunc { return func(namespace string, options metav1.ListOptions) ([]*extensions.ReplicaSet, error) { rsList, err := c.Extensions().ReplicaSets(namespace).List(options) if err != nil { @@ -547,14 +547,14 @@ func podListFromClient(c clientset.Interface) podListFunc { } // TODO: switch this to full namespacers -type rsListFunc func(string, metav1.ListOptions) ([]*extensions.ReplicaSet, error) +type RsListFunc func(string, metav1.ListOptions) ([]*extensions.ReplicaSet, error) type podListFunc func(string, metav1.ListOptions) (*v1.PodList, error) // ListReplicaSets returns a slice of RSes the given deployment targets. // Note that this does NOT attempt to reconcile ControllerRef (adopt/orphan), // because only the controller itself should do that. // However, it does filter out anything whose ControllerRef doesn't match. -func ListReplicaSets(deployment *extensions.Deployment, getRSList rsListFunc) ([]*extensions.ReplicaSet, error) { +func ListReplicaSets(deployment *extensions.Deployment, getRSList RsListFunc) ([]*extensions.ReplicaSet, error) { // TODO: Right now we list replica sets by their labels. We should list them by selector, i.e. the replica set's selector // should be a superset of the deployment's selector, see https://github.com/kubernetes/kubernetes/issues/19830. namespace := deployment.Namespace