func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) { names := sets.String{} for i, pod := range pods { var errlist field.ErrorList if errs := validation.ValidatePod(pod); len(errs) != 0 { errlist = append(errlist, errs...) // If validation fails, don't trust it any further - // even Name could be bad. } else { name := kubecontainer.GetPodFullName(pod) if names.Has(name) { // TODO: when validation becomes versioned, this gets a bit // more complicated. errlist = append(errlist, field.Duplicate(field.NewPath("metadata", "name"), pod.Name)) } else { names.Insert(name) } } if len(errlist) > 0 { name := bestPodIdentString(pod) err := errlist.ToAggregate() glog.Warningf("Pod[%d] (%s) from %s failed validation, ignoring: %v", i+1, name, source, err) recorder.Eventf(pod, api.EventTypeWarning, kubecontainer.FailedValidation, "Error validating pod %s from %s, ignoring: %v", name, source, err) continue } filtered = append(filtered, pod) } return }
func TestExtractPodsFromHTTP(t *testing.T) { hostname := "different-value" grace := int64(30) var testCases = []struct { desc string pods runtime.Object expected kubetypes.PodUpdate }{ { desc: "Single pod", pods: &api.Pod{ TypeMeta: unversioned.TypeMeta{ Kind: "Pod", APIVersion: "", }, ObjectMeta: api.ObjectMeta{ Name: "foo", UID: "111", Namespace: "mynamespace", }, Spec: api.PodSpec{ NodeName: hostname, Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}}, SecurityContext: &api.PodSecurityContext{}, }, Status: api.PodStatus{ Phase: api.PodPending, }, }, expected: CreatePodUpdate(kubetypes.SET, kubetypes.HTTPSource, &api.Pod{ ObjectMeta: api.ObjectMeta{ UID: "111", Name: "foo" + "-" + hostname, Namespace: "mynamespace", Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "111"}, SelfLink: getSelfLink("foo-"+hostname, "mynamespace"), }, Spec: api.PodSpec{ NodeName: hostname, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, SecurityContext: &api.PodSecurityContext{}, TerminationGracePeriodSeconds: &grace, Containers: []api.Container{{ Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", ImagePullPolicy: "Always", }}, }, Status: api.PodStatus{ Phase: api.PodPending, }, }), }, { desc: "Multiple pods", pods: &api.PodList{ TypeMeta: unversioned.TypeMeta{ Kind: "PodList", APIVersion: "", }, Items: []api.Pod{ { ObjectMeta: api.ObjectMeta{ Name: "foo", UID: "111", }, Spec: api.PodSpec{ NodeName: hostname, Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}}, SecurityContext: &api.PodSecurityContext{}, }, Status: api.PodStatus{ Phase: api.PodPending, }, }, { ObjectMeta: api.ObjectMeta{ Name: "bar", UID: "222", }, Spec: api.PodSpec{ NodeName: hostname, Containers: []api.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: ""}}, SecurityContext: &api.PodSecurityContext{}, }, Status: api.PodStatus{ Phase: api.PodPending, }, }, }, }, expected: CreatePodUpdate(kubetypes.SET, kubetypes.HTTPSource, &api.Pod{ ObjectMeta: api.ObjectMeta{ UID: "111", Name: "foo" + "-" + hostname, Namespace: "default", Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "111"}, SelfLink: getSelfLink("foo-"+hostname, kubetypes.NamespaceDefault), }, Spec: api.PodSpec{ NodeName: hostname, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, Containers: []api.Container{{ Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", ImagePullPolicy: "Always", }}, }, Status: api.PodStatus{ Phase: api.PodPending, }, }, &api.Pod{ ObjectMeta: api.ObjectMeta{ UID: "222", Name: "bar" + "-" + hostname, Namespace: "default", Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "222"}, SelfLink: getSelfLink("bar-"+hostname, kubetypes.NamespaceDefault), }, Spec: api.PodSpec{ NodeName: hostname, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, Containers: []api.Container{{ Name: "2", Image: "bar:bartag", TerminationMessagePath: "/dev/termination-log", ImagePullPolicy: "IfNotPresent", }}, }, Status: api.PodStatus{ Phase: api.PodPending, }, }), }, } for _, testCase := range testCases { var versionedPods runtime.Object err := testapi.Default.Converter().Convert(&testCase.pods, &versionedPods) if err != nil { t.Fatalf("%s: error in versioning the pods: %s", testCase.desc, err) } data, err := runtime.Encode(testapi.Default.Codec(), versionedPods) if err != nil { t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err) } fakeHandler := utiltesting.FakeHandler{ StatusCode: 200, ResponseBody: string(data), } testServer := httptest.NewServer(&fakeHandler) defer testServer.Close() ch := make(chan interface{}, 1) c := sourceURL{testServer.URL, http.Header{}, hostname, ch, nil, 0, http.DefaultClient} if err := c.extractFromURL(); err != nil { t.Errorf("%s: Unexpected error: %v", testCase.desc, err) continue } update := (<-ch).(kubetypes.PodUpdate) if !api.Semantic.DeepEqual(testCase.expected, update) { t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update) } for _, pod := range update.Pods { if errs := validation.ValidatePod(pod); len(errs) != 0 { t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, pod, errs.ToAggregate()) } } } }