// checkAndUpdatePod updates existing, and: // * if ref makes a meaningful change, returns needUpdate=true // * if ref makes no meaningful change, but changes the pod status, returns needReconcile=true // * else return both false // Now, needUpdate and needReconcile should never be both true func checkAndUpdatePod(existing, ref *api.Pod) (needUpdate, needReconcile bool) { // TODO: it would be better to update the whole object and only preserve certain things // like the source annotation or the UID (to ensure safety) if !podsDifferSemantically(existing, ref) { // this is not an update // Only check reconcile when it is not an update, because if the pod is going to // be updated, an extra reconcile is unnecessary if !reflect.DeepEqual(existing.Status, ref.Status) { // Pod with changed pod status needs reconcile, because kubelet should // be the source of truth of pod status. existing.Status = ref.Status needReconcile = true } return } // this is an update // Overwrite the first-seen time with the existing one. This is our own // internal annotation, there is no need to update. ref.Annotations[kubetypes.ConfigFirstSeenAnnotationKey] = existing.Annotations[kubetypes.ConfigFirstSeenAnnotationKey] existing.Spec = ref.Spec existing.Labels = ref.Labels existing.DeletionTimestamp = ref.DeletionTimestamp existing.DeletionGracePeriodSeconds = ref.DeletionGracePeriodSeconds existing.Status = ref.Status updateAnnotations(existing, ref) needUpdate = true return }
// checkAndUpdatePod updates existing if ref makes a meaningful change and returns true, or // returns false if there was no update. func checkAndUpdatePod(existing, ref *api.Pod) bool { // TODO: it would be better to update the whole object and only preserve certain things // like the source annotation or the UID (to ensure safety) if reflect.DeepEqual(existing.Spec, ref.Spec) && reflect.DeepEqual(existing.DeletionTimestamp, ref.DeletionTimestamp) && reflect.DeepEqual(existing.DeletionGracePeriodSeconds, ref.DeletionGracePeriodSeconds) { return false } // this is an update existing.Spec = ref.Spec existing.DeletionTimestamp = ref.DeletionTimestamp existing.DeletionGracePeriodSeconds = ref.DeletionGracePeriodSeconds return true }
// checkAndUpdatePod updates existing if ref makes a meaningful change and returns true, or // returns false if there was no update. func checkAndUpdatePod(existing, ref *api.Pod) bool { // TODO: it would be better to update the whole object and only preserve certain things // like the source annotation or the UID (to ensure safety) if !podsDifferSemantically(existing, ref) { return false } // this is an update // Overwrite the first-seen time with the existing one. This is our own // internal annotation, there is no need to update. ref.Annotations[kubelet.ConfigFirstSeenAnnotationKey] = existing.Annotations[kubelet.ConfigFirstSeenAnnotationKey] existing.Spec = ref.Spec existing.DeletionTimestamp = ref.DeletionTimestamp existing.DeletionGracePeriodSeconds = ref.DeletionGracePeriodSeconds updateAnnotations(existing, ref) return true }
func TestSyncBatchNoDeadlock(t *testing.T) { client := &testclient.Fake{} m := newTestManager(client) // Setup fake client. var ret api.Pod var err error client.AddReactor("*", "pods", func(action testclient.Action) (bool, runtime.Object, error) { switch action := action.(type) { case testclient.GetAction: assert.Equal(t, testPod.Name, action.GetName(), "Unexpeted GetAction: %+v", action) case testclient.UpdateAction: assert.Equal(t, testPod.Name, action.GetObject().(*api.Pod).Name, "Unexpeted UpdateAction: %+v", action) default: assert.Fail(t, "Unexpected Action: %+v", action) } return true, &ret, err }) pod := new(api.Pod) *pod = *testPod pod.Status.ContainerStatuses = []api.ContainerStatus{{State: api.ContainerState{Running: &api.ContainerStateRunning{}}}} getAction := testclient.GetActionImpl{ActionImpl: testclient.ActionImpl{Verb: "get", Resource: "pods"}} updateAction := testclient.UpdateActionImpl{ActionImpl: testclient.ActionImpl{Verb: "update", Resource: "pods", Subresource: "status"}} // Pod not found. ret = *pod err = errors.NewNotFound(api.Resource("pods"), pod.Name) m.SetPodStatus(pod, getRandomPodStatus()) m.testSyncBatch() verifyActions(t, client, []testclient.Action{getAction}) client.ClearActions() // Pod was recreated. ret.UID = "other_pod" err = nil m.SetPodStatus(pod, getRandomPodStatus()) m.testSyncBatch() verifyActions(t, client, []testclient.Action{getAction}) client.ClearActions() // Pod not deleted (success case). ret = *pod m.SetPodStatus(pod, getRandomPodStatus()) m.testSyncBatch() verifyActions(t, client, []testclient.Action{getAction, updateAction}) client.ClearActions() // Pod is terminated, but still running. pod.DeletionTimestamp = new(unversioned.Time) m.SetPodStatus(pod, getRandomPodStatus()) m.testSyncBatch() verifyActions(t, client, []testclient.Action{getAction, updateAction}) client.ClearActions() // Pod is terminated successfully. pod.Status.ContainerStatuses[0].State.Running = nil pod.Status.ContainerStatuses[0].State.Terminated = &api.ContainerStateTerminated{} m.SetPodStatus(pod, getRandomPodStatus()) m.testSyncBatch() verifyActions(t, client, []testclient.Action{getAction, updateAction}) client.ClearActions() // Error case. err = fmt.Errorf("intentional test error") m.SetPodStatus(pod, getRandomPodStatus()) m.testSyncBatch() verifyActions(t, client, []testclient.Action{getAction}) client.ClearActions() }