func addUpdatePodsReactor(fakeClient *fake.Clientset) *fake.Clientset { fakeClient.AddReactor("update", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { obj := action.(testclient.UpdateAction).GetObject().(*api.Pod) return true, obj, nil }) return fakeClient }
func addUpdateRSReactor(fakeClient *fake.Clientset) *fake.Clientset { fakeClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { obj := action.(testclient.UpdateAction).GetObject().(*extensions.ReplicaSet) return true, obj, nil }) return fakeClient }
func TestSyncBatchIgnoresNotFound(t *testing.T) { client := fake.Clientset{} syncer := newTestManager(&client) client.AddReactor("get", "pods", func(action core.Action) (bool, runtime.Object, error) { return true, nil, errors.NewNotFound(api.Resource("pods"), "test-pod") }) syncer.SetPodStatus(getTestPod(), getRandomPodStatus()) syncer.testSyncBatch() verifyActions(t, syncer.kubeClient, []core.Action{ core.GetActionImpl{ActionImpl: core.ActionImpl{Verb: "get", Resource: unversioned.GroupVersionResource{Resource: "pods"}}}, }) }
func addGetRSReactor(fakeClient *fake.Clientset, obj runtime.Object) *fake.Clientset { rsList, ok := obj.(*extensions.ReplicaSetList) fakeClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { name := action.(testclient.GetAction).GetName() if ok { for _, rs := range rsList.Items { if rs.Name == name { return true, &rs, nil } } } return false, nil, fmt.Errorf("could not find the requested replica set: %s", name) }) return fakeClient }
func addListPodsReactor(fakeClient *fake.Clientset, obj runtime.Object) *fake.Clientset { fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { return true, obj, nil }) return fakeClient }
func TestDeploymentController_scaleDownOldReplicaSetsForRollingUpdate(t *testing.T) { tests := []struct { deploymentReplicas int maxUnavailable intstr.IntOrString readyPods int oldReplicas int scaleExpected bool expectedOldReplicas int }{ { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(0), readyPods: 10, oldReplicas: 10, scaleExpected: true, expectedOldReplicas: 9, }, { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), readyPods: 10, oldReplicas: 10, scaleExpected: true, expectedOldReplicas: 8, }, { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), readyPods: 8, oldReplicas: 10, scaleExpected: false, }, { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), readyPods: 10, oldReplicas: 0, scaleExpected: false, }, { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), readyPods: 1, oldReplicas: 10, scaleExpected: false, }, } for i, test := range tests { t.Logf("executing scenario %d", i) oldRS := rs("foo-v2", test.oldReplicas, nil, noTimestamp) allRSs := []*exp.ReplicaSet{oldRS} oldRSs := []*exp.ReplicaSet{oldRS} deployment := deployment("foo", test.deploymentReplicas, intstr.FromInt(0), test.maxUnavailable, map[string]string{"foo": "bar"}) fakeClientset := fake.Clientset{} fakeClientset.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { switch action.(type) { case core.ListAction: podList := &api.PodList{} for podIndex := 0; podIndex < test.readyPods; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-pod-%d", oldRS.Name, podIndex), Labels: map[string]string{"foo": "bar"}, }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionTrue, }, }, }, }) } return true, podList, nil } return false, nil, nil }) controller := &DeploymentController{ client: &fakeClientset, eventRecorder: &record.FakeRecorder{}, } scaled, err := controller.scaleDownOldReplicaSetsForRollingUpdate(allRSs, oldRSs, &deployment) if err != nil { t.Errorf("unexpected error: %v", err) continue } if !test.scaleExpected { if scaled != 0 { t.Errorf("unexpected scaling: %v", fakeClientset.Actions()) } continue } if test.scaleExpected && scaled == 0 { t.Errorf("expected scaling to occur; actions: %v", fakeClientset.Actions()) continue } // There are both list and update actions logged, so extract the update // action for verification. var updateAction core.UpdateAction for _, action := range fakeClientset.Actions() { switch a := action.(type) { case core.UpdateAction: if updateAction != nil { t.Errorf("expected only 1 update action; had %v and found %v", updateAction, a) } else { updateAction = a } } } if updateAction == nil { t.Errorf("expected an update action") continue } updated := updateAction.GetObject().(*exp.ReplicaSet) if e, a := test.expectedOldReplicas, int(updated.Spec.Replicas); e != a { t.Errorf("expected update to %d replicas, got %d", e, a) } } }
func TestDeploymentController_cleanupUnhealthyReplicas(t *testing.T) { tests := []struct { oldReplicas int readyPods int unHealthyPods int maxCleanupCount int cleanupCountExpected int }{ { oldReplicas: 10, readyPods: 8, unHealthyPods: 2, maxCleanupCount: 1, cleanupCountExpected: 1, }, { oldReplicas: 10, readyPods: 8, unHealthyPods: 2, maxCleanupCount: 3, cleanupCountExpected: 2, }, { oldReplicas: 10, readyPods: 8, unHealthyPods: 2, maxCleanupCount: 0, cleanupCountExpected: 0, }, { oldReplicas: 10, readyPods: 10, unHealthyPods: 0, maxCleanupCount: 3, cleanupCountExpected: 0, }, } for i, test := range tests { t.Logf("executing scenario %d", i) oldRS := rs("foo-v2", test.oldReplicas, nil, noTimestamp) oldRSs := []*exp.ReplicaSet{oldRS} deployment := deployment("foo", 10, intstr.FromInt(2), intstr.FromInt(2), nil) fakeClientset := fake.Clientset{} fakeClientset.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { switch action.(type) { case core.ListAction: podList := &api.PodList{} for podIndex := 0; podIndex < test.readyPods; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-readyPod-%d", oldRS.Name, podIndex), }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionTrue, }, }, }, }) } for podIndex := 0; podIndex < test.unHealthyPods; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-unHealthyPod-%d", oldRS.Name, podIndex), }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionFalse, }, }, }, }) } return true, podList, nil } return false, nil, nil }) controller := &DeploymentController{ client: &fakeClientset, eventRecorder: &record.FakeRecorder{}, } _, cleanupCount, err := controller.cleanupUnhealthyReplicas(oldRSs, &deployment, 0, int32(test.maxCleanupCount)) if err != nil { t.Errorf("unexpected error: %v", err) continue } if int(cleanupCount) != test.cleanupCountExpected { t.Errorf("expected %v unhealthy replicas been cleaned up, got %v", test.cleanupCountExpected, cleanupCount) continue } } }
func TestDeploymentController_reconcileOldReplicaSets(t *testing.T) { tests := []struct { deploymentReplicas int maxUnavailable intstr.IntOrString oldReplicas int newReplicas int readyPodsFromOldRS int readyPodsFromNewRS int scaleExpected bool expectedOldReplicas int }{ { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(0), oldReplicas: 10, newReplicas: 0, readyPodsFromOldRS: 10, readyPodsFromNewRS: 0, scaleExpected: true, expectedOldReplicas: 9, }, { deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), oldReplicas: 10, newReplicas: 0, readyPodsFromOldRS: 10, readyPodsFromNewRS: 0, scaleExpected: true, expectedOldReplicas: 8, }, { // expect unhealthy replicas from old replica sets been cleaned up deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), oldReplicas: 10, newReplicas: 0, readyPodsFromOldRS: 8, readyPodsFromNewRS: 0, scaleExpected: true, expectedOldReplicas: 8, }, { // expect 1 unhealthy replica from old replica sets been cleaned up, and 1 ready pod been scaled down deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), oldReplicas: 10, newReplicas: 0, readyPodsFromOldRS: 9, readyPodsFromNewRS: 0, scaleExpected: true, expectedOldReplicas: 8, }, { // the unavailable pods from the newRS would not make us scale down old RSs in a further step deploymentReplicas: 10, maxUnavailable: intstr.FromInt(2), oldReplicas: 8, newReplicas: 2, readyPodsFromOldRS: 8, readyPodsFromNewRS: 0, scaleExpected: false, }, } for i, test := range tests { t.Logf("executing scenario %d", i) newSelector := map[string]string{"foo": "new"} oldSelector := map[string]string{"foo": "old"} newRS := rs("foo-new", test.newReplicas, newSelector, noTimestamp) oldRS := rs("foo-old", test.oldReplicas, oldSelector, noTimestamp) oldRSs := []*exp.ReplicaSet{oldRS} allRSs := []*exp.ReplicaSet{oldRS, newRS} deployment := deployment("foo", test.deploymentReplicas, intstr.FromInt(0), test.maxUnavailable, newSelector) fakeClientset := fake.Clientset{} fakeClientset.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { switch action.(type) { case core.ListAction: podList := &api.PodList{} for podIndex := 0; podIndex < test.readyPodsFromOldRS; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-oldReadyPod-%d", oldRS.Name, podIndex), Labels: oldSelector, }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionTrue, }, }, }, }) } for podIndex := 0; podIndex < test.oldReplicas-test.readyPodsFromOldRS; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-oldUnhealthyPod-%d", oldRS.Name, podIndex), Labels: oldSelector, }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionFalse, }, }, }, }) } for podIndex := 0; podIndex < test.readyPodsFromNewRS; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-newReadyPod-%d", oldRS.Name, podIndex), Labels: newSelector, }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionTrue, }, }, }, }) } for podIndex := 0; podIndex < test.oldReplicas-test.readyPodsFromOldRS; podIndex++ { podList.Items = append(podList.Items, api.Pod{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%s-newUnhealthyPod-%d", oldRS.Name, podIndex), Labels: newSelector, }, Status: api.PodStatus{ Conditions: []api.PodCondition{ { Type: api.PodReady, Status: api.ConditionFalse, }, }, }, }) } return true, podList, nil } return false, nil, nil }) controller := &DeploymentController{ client: &fakeClientset, eventRecorder: &record.FakeRecorder{}, } scaled, err := controller.reconcileOldReplicaSets(allRSs, oldRSs, newRS, &deployment) if err != nil { t.Errorf("unexpected error: %v", err) continue } if !test.scaleExpected && scaled { t.Errorf("unexpected scaling: %v", fakeClientset.Actions()) } if test.scaleExpected && !scaled { t.Errorf("expected scaling to occur") continue } continue } }