func (s *podStorage) merge(source string, change interface{}) (adds, updates, deletes, removes, reconciles *kubetypes.PodUpdate) { s.podLock.Lock() defer s.podLock.Unlock() addPods := []*v1.Pod{} updatePods := []*v1.Pod{} deletePods := []*v1.Pod{} removePods := []*v1.Pod{} reconcilePods := []*v1.Pod{} pods := s.pods[source] if pods == nil { pods = make(map[string]*v1.Pod) } // updatePodFunc is the local function which updates the pod cache *oldPods* with new pods *newPods*. // After updated, new pod will be stored in the pod cache *pods*. // Notice that *pods* and *oldPods* could be the same cache. updatePodsFunc := func(newPods []*v1.Pod, oldPods, pods map[string]*v1.Pod) { filtered := filterInvalidPods(newPods, source, s.recorder) for _, ref := range filtered { name := kubecontainer.GetPodFullName(ref) // Annotate the pod with the source before any comparison. if ref.Annotations == nil { ref.Annotations = make(map[string]string) } ref.Annotations[kubetypes.ConfigSourceAnnotationKey] = source if existing, found := oldPods[name]; found { pods[name] = existing needUpdate, needReconcile, needGracefulDelete := checkAndUpdatePod(existing, ref) if needUpdate { updatePods = append(updatePods, existing) } else if needReconcile { reconcilePods = append(reconcilePods, existing) } else if needGracefulDelete { deletePods = append(deletePods, existing) } continue } recordFirstSeenTime(ref) pods[name] = ref addPods = append(addPods, ref) } } update := change.(kubetypes.PodUpdate) // The InitContainers and InitContainerStatuses fields are lost during // serialization and deserialization. They are conveyed via Annotations. // Setting these fields here so that kubelet doesn't have to check for // annotations. if source == kubetypes.ApiserverSource { for _, pod := range update.Pods { if err := podutil.SetInitContainersAndStatuses(pod); err != nil { glog.Error(err) } } } switch update.Op { case kubetypes.ADD, kubetypes.UPDATE, kubetypes.DELETE: if update.Op == kubetypes.ADD { glog.V(4).Infof("Adding new pods from source %s : %v", source, update.Pods) } else if update.Op == kubetypes.DELETE { glog.V(4).Infof("Graceful deleting pods from source %s : %v", source, update.Pods) } else { glog.V(4).Infof("Updating pods from source %s : %v", source, update.Pods) } updatePodsFunc(update.Pods, pods, pods) case kubetypes.REMOVE: glog.V(4).Infof("Removing pods from source %s : %v", source, update.Pods) for _, value := range update.Pods { name := kubecontainer.GetPodFullName(value) if existing, found := pods[name]; found { // this is a delete delete(pods, name) removePods = append(removePods, existing) continue } // this is a no-op } case kubetypes.SET: glog.V(4).Infof("Setting pods for source %s", source) s.markSourceSet(source) // Clear the old map entries by just creating a new map oldPods := pods pods = make(map[string]*v1.Pod) updatePodsFunc(update.Pods, oldPods, pods) for name, existing := range oldPods { if _, found := pods[name]; !found { // this is a delete removePods = append(removePods, existing) } } default: glog.Warningf("Received invalid update type: %v", update) } s.pods[source] = pods adds = &kubetypes.PodUpdate{Op: kubetypes.ADD, Pods: copyPods(addPods), Source: source} updates = &kubetypes.PodUpdate{Op: kubetypes.UPDATE, Pods: copyPods(updatePods), Source: source} deletes = &kubetypes.PodUpdate{Op: kubetypes.DELETE, Pods: copyPods(deletePods), Source: source} removes = &kubetypes.PodUpdate{Op: kubetypes.REMOVE, Pods: copyPods(removePods), Source: source} reconciles = &kubetypes.PodUpdate{Op: kubetypes.RECONCILE, Pods: copyPods(reconcilePods), Source: source} return adds, updates, deletes, removes, reconciles }
}, }, }, } if err := podutil.SetInitContainersAnnotations(pod); err != nil { Expect(err).To(BeNil()) } startedPod := podClient.Create(pod) w, err := podClient.Watch(v1.SingleObject(startedPod.ObjectMeta)) Expect(err).NotTo(HaveOccurred(), "error watching a pod") wr := watch.NewRecorder(w) event, err := watch.Until(framework.PodStartTimeout, wr, conditions.PodCompleted) Expect(err).To(BeNil()) framework.CheckInvariants(wr.Events(), framework.ContainerInitInvariant) endPod := event.Object.(*v1.Pod) if err := podutil.SetInitContainersAndStatuses(endPod); err != nil { Expect(err).To(BeNil()) } Expect(endPod.Status.Phase).To(Equal(v1.PodSucceeded)) _, init := v1.GetPodCondition(&endPod.Status, v1.PodInitialized) Expect(init).NotTo(BeNil()) Expect(init.Status).To(Equal(v1.ConditionTrue)) Expect(len(endPod.Status.InitContainerStatuses)).To(Equal(2)) for _, status := range endPod.Status.InitContainerStatuses { Expect(status.Ready).To(BeTrue()) Expect(status.State.Terminated).NotTo(BeNil()) Expect(status.State.Terminated.ExitCode).To(BeZero()) } })