Пример #1
0
func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) {
	names := util.StringSet{}
	for i, pod := range pods {
		var errlist []error
		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) {
				errlist = append(errlist, fielderrors.NewFieldDuplicate("name", pod.Name))
			} else {
				names.Insert(name)
			}
		}
		if len(errlist) > 0 {
			name := bestPodIdentString(pod)
			err := utilerrors.NewAggregate(errlist)
			glog.Warningf("Pod[%d] (%s) from %s failed validation, ignoring: %v", i+1, name, source, err)
			recorder.Eventf(pod, "failedValidation", "Error validating pod %s from %s, ignoring: %v", name, source, err)
			continue
		}
		filtered = append(filtered, pod)
	}
	return
}
Пример #2
0
func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods api.PodList, err error) {
	json, err := utilyaml.ToJSON(data)
	if err != nil {
		return false, api.PodList{}, err
	}
	obj, err := api.Scheme.Decode(json)
	if err != nil {
		return false, pods, err
	}
	// Check whether the object could be converted to list of pods.
	if _, ok := obj.(*api.PodList); !ok {
		err = fmt.Errorf("invalid pods list: %+v", obj)
		return false, pods, err
	}
	newPods := obj.(*api.PodList)
	// Apply default values and validate pods.
	for i := range newPods.Items {
		newPod := &newPods.Items[i]
		if err = defaultFn(newPod); err != nil {
			return true, pods, err
		}
		if errs := validation.ValidatePod(newPod); len(errs) > 0 {
			err = fmt.Errorf("invalid pod: %v", errs)
			return true, pods, err
		}
	}
	return true, *newPods, err
}
Пример #3
0
func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *api.Pod, err error) {
	// JSON is valid YAML, so this should work for everything.
	json, err := utilyaml.ToJSON(data)
	if err != nil {
		return false, nil, err
	}
	obj, err := api.Scheme.Decode(json)
	if err != nil {
		return false, pod, err
	}
	// Check whether the object could be converted to single pod.
	if _, ok := obj.(*api.Pod); !ok {
		err = fmt.Errorf("invalid pod: %+v", obj)
		return false, pod, err
	}
	newPod := obj.(*api.Pod)
	// Apply default values and validate the pod.
	if err = defaultFn(newPod); err != nil {
		return true, pod, err
	}
	if errs := validation.ValidatePod(newPod); len(errs) > 0 {
		err = fmt.Errorf("invalid pod: %v", errs)
		return true, pod, err
	}
	return true, newPod, nil
}
func TestExtractFromDir(t *testing.T) {
	if !api.PreV1Beta3(testapi.Version()) {
		return
	}
	manifest, expectedPod := exampleManifestAndPod("1")
	manifest2, expectedPod2 := exampleManifestAndPod("2")

	manifests := []v1beta1.ContainerManifest{manifest, manifest2}
	pods := []*api.Pod{expectedPod, expectedPod2}
	files := make([]*os.File, len(manifests))

	dirName, err := ioutil.TempDir("", "foo")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	for i, manifest := range manifests {
		data, err := json.Marshal(manifest)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		file, err := ioutil.TempFile(dirName, manifest.ID)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		name := file.Name()
		if err := file.Close(); err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		ioutil.WriteFile(name, data, 0755)
		files[i] = file
	}

	ch := make(chan interface{}, 1)
	c := sourceFile{dirName, "an-example-host", ch}
	err = c.extractFromPath()
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	update := (<-ch).(kubelet.PodUpdate)
	expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
	sort.Sort(sortedPods(update.Pods))
	sort.Sort(sortedPods(expected.Pods))
	if !api.Semantic.DeepDerivative(expected, update) {
		t.Fatalf("Expected %#v, Got %#v", expected, update)
	}
	for _, pod := range update.Pods {
		if errs := validation.ValidatePod(pod); len(errs) != 0 {
			t.Errorf("Expected no validation errors on %#v, Got %q", pod, errs)
		}
	}
}
Пример #5
0
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
	pod := obj.(*api.Pod)
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.ID, errs)
	}
	return apiserver.MakeAsync(func() (interface{}, error) {
		if err := rs.registry.UpdatePod(*pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(pod.ID)
	}), nil
}
Пример #6
0
func (rs *REST) Update(obj runtime.Object) (<-chan runtime.Object, error) {
	pod := obj.(*api.Pod)
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.ID, errs)
	}
	return apiserver.MakeAsync(func() (runtime.Object, error) {
		if err := rs.registry.UpdatePod(pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(pod.ID)
	}), nil
}
Пример #7
0
func validateObject(path string, obj runtime.Object, t *testing.T) {
	// if an object requires a namespace server side, be sure that it is filled in for validation
	if validation.HasObjectMeta(obj) {
		namespaceRequired, err := validation.GetRequiresNamespace(obj)
		if err != nil {
			t.Errorf("Expected no error, Got %v", err)
			return
		}

		if namespaceRequired {
			objectMeta, err := kapi.ObjectMetaFor(obj)
			if err != nil {
				t.Errorf("Expected no error, Got %v", err)
				return
			}

			objectMeta.Namespace = kapi.NamespaceDefault
		}
	}

	switch typedObj := obj.(type) {
	case *kapi.Pod:
		if errors := kvalidation.ValidatePod(typedObj); len(errors) > 0 {
			t.Errorf("%s did not validate correctly: %v", path, errors)
		}

	case *kapi.Service:
		if errors := kvalidation.ValidateService(typedObj); len(errors) > 0 {
			t.Errorf("%s did not validate correctly: %v", path, errors)
		}

	case *kapi.List, *imageapi.ImageStreamList:
		if list, err := runtime.ExtractList(typedObj); err == nil {
			runtime.DecodeList(list, kapi.Scheme)
			for i := range list {
				validateObject(path, list[i], t)
			}

		} else {
			t.Errorf("Expected no error, Got %v", err)

		}

	default:
		if errors := validation.Validator.Validate(obj); len(errors) > 0 {
			t.Errorf("%s with %v did not validate correctly: %v", path, reflect.TypeOf(obj), errors)
		}
	}

}
Пример #8
0
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
	pod := obj.(*api.Pod)
	if !api.ValidNamespace(ctx, &pod.ObjectMeta) {
		return nil, errors.NewConflict("pod", pod.Namespace, fmt.Errorf("Pod.Namespace does not match the provided context"))
	}
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.Name, errs)
	}
	return apiserver.MakeAsync(func() (runtime.Object, error) {
		if err := rs.registry.UpdatePod(ctx, pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(ctx, pod.Name)
	}), nil
}
func validateObject(obj runtime.Object) (errors []error) {
	switch t := obj.(type) {
	case *api.ReplicationController:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateReplicationController(t)
	case *api.ReplicationControllerList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Service:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateService(t)
	case *api.ServiceList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Pod:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidatePod(t)
	case *api.PodList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.PersistentVolume:
		errors = validation.ValidatePersistentVolume(t)
	case *api.PersistentVolumeClaim:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidatePersistentVolumeClaim(t)
	case *api.PodTemplate:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidatePodTemplate(t)
	default:
		return []error{fmt.Errorf("no validation defined for %#v", obj)}
	}
	return errors
}
Пример #10
0
func TestCompatibility_v1_Pod(t *testing.T) {
	// Test "spec.host" -> "spec.nodeName"
	expectedHost := "my-host"
	// Test "spec.serviceAccount" -> "spec.serviceAccountName"
	expectedServiceAccount := "my-service-account"
	// Test "tcp" protocol gets converted to "TCP" and validated
	originalProtocol := "tcp"
	expectedProtocol := "TCP"

	input := []byte(fmt.Sprintf(`
{
	"kind":"Pod",
	"apiVersion":"v1",
	"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
	"spec": {
		"host":"%s",
		"serviceAccount":"%s",
		"containers":[{
			"name":"my-container-name",
			"image":"my-container-image",
			"ports":[{"containerPort":1,"protocol":"%s"}]
		}]
	}
}
`, expectedHost, expectedServiceAccount, originalProtocol))

	t.Log("Testing 1.0.0 v1 migration added in PR #3592")
	testCompatibility(
		t, "v1", input,
		func(obj runtime.Object) fielderrors.ValidationErrorList {
			return validation.ValidatePod(obj.(*api.Pod))
		},
		map[string]string{
			"spec.host":     expectedHost,
			"spec.nodeName": expectedHost,

			"spec.serviceAccount":     expectedServiceAccount,
			"spec.serviceAccountName": expectedServiceAccount,

			"spec.containers[0].ports[0].protocol": expectedProtocol,
		},
	)
}
Пример #11
0
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
	pod := obj.(*api.Pod)
	if len(pod.ID) == 0 {
		pod.ID = uuid.NewUUID().String()
	}
	pod.DesiredState.Manifest.ID = pod.ID
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.ID, errs)
	}

	pod.CreationTimestamp = util.Now()

	return apiserver.MakeAsync(func() (interface{}, error) {
		if err := rs.registry.CreatePod(*pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(pod.ID)
	}), nil
}
Пример #12
0
func (rs *REST) Create(obj runtime.Object) (<-chan runtime.Object, error) {
	pod := obj.(*api.Pod)
	pod.DesiredState.Manifest.UUID = uuid.NewUUID().String()
	if len(pod.ID) == 0 {
		pod.ID = pod.DesiredState.Manifest.UUID
	}
	pod.DesiredState.Manifest.ID = pod.ID
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.ID, errs)
	}

	pod.CreationTimestamp = util.Now()

	return apiserver.MakeAsync(func() (runtime.Object, error) {
		if err := rs.registry.CreatePod(pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(pod.ID)
	}), nil
}
Пример #13
0
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
	pod := obj.(*api.Pod)
	if !api.ValidNamespace(ctx, &pod.ObjectMeta) {
		return nil, errors.NewConflict("pod", pod.Namespace, fmt.Errorf("Pod.Namespace does not match the provided context"))
	}
	api.FillObjectMetaSystemFields(ctx, &pod.ObjectMeta)
	if len(pod.Name) == 0 {
		// TODO properly handle auto-generated names.
		// See https://github.com/GoogleCloudPlatform/kubernetes/issues/148 170 & 1135
		pod.Name = string(pod.UID)
	}
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.Name, errs)
	}
	return apiserver.MakeAsync(func() (runtime.Object, error) {
		if err := rs.registry.CreatePod(ctx, pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(ctx, pod.Name)
	}), nil
}
Пример #14
0
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
	pod := obj.(*api.Pod)
	if !api.ValidNamespace(ctx, &pod.ObjectMeta) {
		return nil, errors.NewConflict("pod", pod.Namespace, fmt.Errorf("Pod.Namespace does not match the provided context"))
	}
	pod.DesiredState.Manifest.UUID = util.NewUUID().String()
	if len(pod.Name) == 0 {
		pod.Name = pod.DesiredState.Manifest.UUID
	}
	pod.DesiredState.Manifest.ID = pod.Name
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		return nil, errors.NewInvalid("pod", pod.Name, errs)
	}
	pod.CreationTimestamp = util.Now()

	return apiserver.MakeAsync(func() (runtime.Object, error) {
		if err := rs.registry.CreatePod(ctx, pod); err != nil {
			return nil, err
		}
		return rs.registry.GetPod(ctx, pod.Name)
	}), nil
}
Пример #15
0
func validateObject(obj runtime.Object) (errors []error) {
	ctx := api.NewDefaultContext()
	switch t := obj.(type) {
	case *api.ReplicationController:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateReplicationController(t)
	case *api.ReplicationControllerList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Service:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		api.ValidNamespace(ctx, &t.ObjectMeta)
		errors = validation.ValidateService(t)
	case *api.ServiceList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Pod:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		api.ValidNamespace(ctx, &t.ObjectMeta)
		errors = validation.ValidatePod(t)
	case *api.PodList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	default:
		return []error{fmt.Errorf("no validation defined for %#v", obj)}
	}
	return errors
}
Пример #16
0
func TestExtractFromDir(t *testing.T) {
	manifest, expectedPod := ExampleManifestAndPod("1")
	manifest2, expectedPod2 := ExampleManifestAndPod("2")

	manifests := []v1beta1.ContainerManifest{manifest, manifest2}
	pods := []api.Pod{expectedPod, expectedPod2}
	files := make([]*os.File, len(manifests))

	dirName, err := ioutil.TempDir("", "foo")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	for i, manifest := range manifests {
		data, err := json.Marshal(manifest)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		file, err := ioutil.TempFile(dirName, manifest.ID)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		name := file.Name()
		if err := file.Close(); err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		ioutil.WriteFile(name, data, 0755)
		files[i] = file
	}

	ch := make(chan interface{}, 1)
	c := sourceFile{dirName, ch}
	err = c.extractFromPath()
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	update := (<-ch).(kubelet.PodUpdate)
	for i := range update.Pods {
		// Pod name is generated with hash and is unique. Skip the comparision
		// here by setting it to a simple value.
		update.Pods[i].Name = manifests[i].ID
		update.Pods[i].SelfLink = ""
	}
	expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
	for i := range expected.Pods {
		// Pod name is generated with hash and is unique. Skip the comparision
		// here by setting it to a simple value.
		expected.Pods[i].Name = manifests[i].ID
	}
	sort.Sort(sortedPods(update.Pods))
	sort.Sort(sortedPods(expected.Pods))
	if !api.Semantic.DeepDerivative(expected, update) {
		t.Fatalf("Expected %#v, Got %#v", expected, update)
	}
	for i := range update.Pods {
		if errs := validation.ValidatePod(&update.Pods[i]); len(errs) != 0 {
			t.Errorf("Expected no validation errors on %#v, Got %q", update.Pods[i], errs)
		}
	}
}
Пример #17
0
// Validate validates a new pod.
func (podStrategy) Validate(obj runtime.Object) errors.ValidationErrorList {
	pod := obj.(*api.Pod)
	return validation.ValidatePod(pod)
}
Пример #18
0
func TestReadPodsFromFile(t *testing.T) {
	hostname := "random-test-hostname"
	var testCases = []struct {
		desc     string
		pod      runtime.Object
		expected kubelet.PodUpdate
	}{
		{
			desc: "Simple pod",
			pod: &api.Pod{
				TypeMeta: api.TypeMeta{
					Kind:       "Pod",
					APIVersion: "",
				},
				ObjectMeta: api.ObjectMeta{
					Name:      "test",
					UID:       "12345",
					Namespace: "mynamespace",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
				},
			},
			expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:      "test-" + hostname,
					UID:       "12345",
					Namespace: "mynamespace",
					SelfLink:  getSelfLink("test-"+hostname, "mynamespace"),
				},
				Spec: api.PodSpec{
					NodeName:      hostname,
					RestartPolicy: api.RestartPolicyAlways,
					DNSPolicy:     api.DNSClusterFirst,
					Containers: []api.Container{{
						Name:  "image",
						Image: "test/image",
						TerminationMessagePath: "/dev/termination-log",
						ImagePullPolicy:        "IfNotPresent",
						SecurityContext:        securitycontext.ValidSecurityContextWithContainerDefaults()}},
				},
			}),
		},
		{
			desc: "Pod without ID",
			pod: &api.Pod{
				TypeMeta: api.TypeMeta{
					Kind:       "Pod",
					APIVersion: "",
				},
				ObjectMeta: api.ObjectMeta{
					// No name
					UID: "12345",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
				},
			},
			expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:      "12345-" + hostname,
					UID:       "12345",
					Namespace: kubelet.NamespaceDefault,
					SelfLink:  getSelfLink("12345-"+hostname, kubelet.NamespaceDefault),
				},
				Spec: api.PodSpec{
					NodeName:      hostname,
					RestartPolicy: api.RestartPolicyAlways,
					DNSPolicy:     api.DNSClusterFirst,
					Containers: []api.Container{{
						Name:  "image",
						Image: "test/image",
						TerminationMessagePath: "/dev/termination-log",
						ImagePullPolicy:        "IfNotPresent",
						SecurityContext:        securitycontext.ValidSecurityContextWithContainerDefaults()}},
				},
			}),
		},
	}

	for _, testCase := range testCases {
		func() {
			var versionedPod runtime.Object
			err := testapi.Converter().Convert(&testCase.pod, &versionedPod)
			if err != nil {
				t.Fatalf("error in versioning the pod: %s", testCase.desc, err)
			}
			fileContents, err := testapi.Codec().Encode(versionedPod)
			if err != nil {
				t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err)
			}

			file := writeTestFile(t, os.TempDir(), "test_pod_config", string(fileContents))
			defer os.Remove(file.Name())

			ch := make(chan interface{})
			NewSourceFile(file.Name(), hostname, time.Millisecond, ch)
			select {
			case got := <-ch:
				update := got.(kubelet.PodUpdate)
				for _, pod := range update.Pods {
					if errs := validation.ValidatePod(pod); len(errs) > 0 {
						t.Errorf("%s: Invalid pod %#v, %#v", testCase.desc, pod, errs)
					}
				}
				if !api.Semantic.DeepEqual(testCase.expected, update) {
					t.Errorf("%s: Expected %#v, Got %#v", testCase.desc, testCase.expected, update)
				}
			case <-time.After(time.Second):
				t.Errorf("%s: Expected update, timeout instead", testCase.desc)
			}
		}()
	}
}
Пример #19
0
// ValidateUpdate is the default update validation for an end user.
func (podStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
	errorList := validation.ValidatePod(obj.(*api.Pod))
	return append(errorList, validation.ValidatePodUpdate(obj.(*api.Pod), old.(*api.Pod))...)
}
Пример #20
0
// Validate validates a new pod.
func (podStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
	pod := obj.(*api.Pod)
	return validation.ValidatePod(pod)
}
Пример #21
0
func TestReadContainerManifestFromFile(t *testing.T) {
	// ContainerManifest is supported only for pre v1beta3 versions.
	if !api.PreV1Beta3(testapi.Version()) {
		return
	}
	hostname := "random-test-hostname"
	var testCases = []struct {
		desc         string
		fileContents string
		expected     kubelet.PodUpdate
	}{
		{
			desc: "Manifest",
			fileContents: fmt.Sprintf(`{
					"version": "%s",
					"uuid": "12345",
					"id": "test",
					"containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}]
				}`, testapi.Version()),
			expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:      "test-" + hostname,
					UID:       "12345",
					Namespace: kubelet.NamespaceDefault,
					SelfLink:  getSelfLink("test-"+hostname, kubelet.NamespaceDefault),
				},
				Spec: api.PodSpec{
					Host:          hostname,
					RestartPolicy: api.RestartPolicyAlways,
					DNSPolicy:     api.DNSClusterFirst,
					Containers: []api.Container{{
						Name:  "image",
						Image: "test/image",
						TerminationMessagePath: "/dev/termination-log",
						ImagePullPolicy:        "Always"}},
				},
			}),
		},
		{
			desc: "Manifest without ID",
			fileContents: fmt.Sprintf(`{
						"version": "%s",
						"uuid": "12345",
						"containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}]
					}`, testapi.Version()),
			expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:      "12345-" + hostname,
					UID:       "12345",
					Namespace: kubelet.NamespaceDefault,
					SelfLink:  getSelfLink("12345-"+hostname, kubelet.NamespaceDefault),
				},
				Spec: api.PodSpec{
					Host:          hostname,
					RestartPolicy: api.RestartPolicyAlways,
					DNSPolicy:     api.DNSClusterFirst,
					Containers: []api.Container{{
						Name:  "image",
						Image: "test/image",
						TerminationMessagePath: "/dev/termination-log",
						ImagePullPolicy:        "Always"}},
				},
			}),
		},
	}

	for _, testCase := range testCases {
		func() {
			file := writeTestFile(t, os.TempDir(), "test_pod_config", testCase.fileContents)
			defer os.Remove(file.Name())

			ch := make(chan interface{})
			NewSourceFile(file.Name(), hostname, time.Millisecond, ch)
			select {
			case got := <-ch:
				update := got.(kubelet.PodUpdate)
				for _, pod := range update.Pods {
					if errs := validation.ValidatePod(pod); len(errs) > 0 {
						t.Errorf("%s: Invalid pod %#v, %#v", testCase.desc, pod, errs)
					}
				}
				if !api.Semantic.DeepEqual(testCase.expected, update) {
					t.Errorf("%s: Expected %#v, Got %#v", testCase.desc, testCase.expected, update)
				}
			case <-time.After(time.Second):
				t.Errorf("%s: Expected update, timeout instead", testCase.desc)
			}
		}()
	}
}
Пример #22
0
func TestExtractFromHTTP(t *testing.T) {
	hostname, _ := os.Hostname()
	hostname = strings.ToLower(hostname)

	var testCases = []struct {
		desc      string
		manifests interface{}
		expected  kubelet.PodUpdate
	}{
		{
			desc: "Single manifest",
			manifests: v1beta1.ContainerManifest{Version: "v1beta1", ID: "foo", UUID: "111",
				Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "foobar",
						SelfLink:  "/api/v1beta1/pods/foo",
					},
					Spec: api.PodSpec{
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always"}},
					},
				}),
		},
		{
			desc:      "Single manifest without ID",
			manifests: api.ContainerManifest{Version: "v1beta1", UUID: "111"},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "111" + "-" + hostname,
						Namespace: "foobar",
					},
					Spec: api.PodSpec{
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
					},
				}),
		},
		{
			desc: "Single manifest with v1beta2",
			manifests: v1beta1.ContainerManifest{Version: "v1beta2", ID: "foo", UUID: "111",
				Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "foobar",
						SelfLink:  "/api/v1beta1/pods/foo",
					},
					Spec: api.PodSpec{
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always"}},
					},
				}),
		},
		{
			desc: "Multiple manifests",
			manifests: []v1beta1.ContainerManifest{
				{Version: "v1beta1", ID: "foo", UUID: "111",
					Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
				{Version: "v1beta1", ID: "bar", UUID: "222",
					Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: ""}}},
			},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "foobar",
						SelfLink:  "/api/v1beta1/pods/foo",
					},
					Spec: api.PodSpec{
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always"}},
					},
				},
				api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "222",
						Name:      "bar" + "-" + hostname,
						Namespace: "foobar",
						SelfLink:  "/api/v1beta1/pods/bar",
					},
					Spec: api.PodSpec{
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "IfNotPresent"}},
					},
				}),
		},
		{
			desc:      "Empty Array",
			manifests: []v1beta1.ContainerManifest{},
			expected:  CreatePodUpdate(kubelet.SET, kubelet.HTTPSource),
		},
	}

	for _, testCase := range testCases {
		data, err := json.Marshal(testCase.manifests)
		if err != nil {
			t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err)
		}
		fakeHandler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: string(data),
		}
		testServer := httptest.NewServer(&fakeHandler)
		defer testServer.Close()
		ch := make(chan interface{}, 1)
		c := sourceURL{testServer.URL, ch, nil}
		if err := c.extractFromURL(); err != nil {
			t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
			continue
		}
		update := (<-ch).(kubelet.PodUpdate)

		for i := range update.Pods {
			// There's no way to provide namespace in ContainerManifest, so
			// it will be defaulted.
			if update.Pods[i].Namespace != kubelet.NamespaceDefault {
				t.Errorf("Unexpected namespace: %s", update.Pods[0].Namespace)
			}
			update.Pods[i].ObjectMeta.Namespace = "foobar"
		}
		if !api.Semantic.DeepEqual(testCase.expected, update) {
			t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
		}
		for i := range update.Pods {
			if errs := validation.ValidatePod(&update.Pods[i]); len(errs) != 0 {
				t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, update.Pods[i], errors.NewAggregate(errs))
			}
		}
	}
}
Пример #23
0
func TestExtractPodsFromHTTP(t *testing.T) {
	hostname := "different-value"

	var testCases = []struct {
		desc     string
		pods     runtime.Object
		expected kubelet.PodUpdate
	}{
		{
			desc: "Single pod",
			pods: &api.Pod{
				TypeMeta: api.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}},
				},
			},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "mynamespace",

						SelfLink: getSelfLink("foo-"+hostname, "mynamespace"),
					},
					Spec: api.PodSpec{
						NodeName:      hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always",
						}},
					},
				}),
		},
		{
			desc: "Multiple pods",
			pods: &api.PodList{
				TypeMeta: api.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}},
						},
					},
					{
						ObjectMeta: api.ObjectMeta{
							Name: "bar",
							UID:  "222",
						},
						Spec: api.PodSpec{
							NodeName:   hostname,
							Containers: []api.Container{{Name: "2", Image: "bar", ImagePullPolicy: ""}},
						},
					},
				},
			},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "default",

						SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						NodeName:      hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always",
						}},
					},
				},
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "222",
						Name:      "bar" + "-" + hostname,
						Namespace: "default",

						SelfLink: getSelfLink("bar-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						NodeName:      hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "2",
							Image: "bar",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "IfNotPresent",
						}},
					},
				}),
		},
	}

	for _, testCase := range testCases {
		var versionedPods runtime.Object
		err := testapi.Converter().Convert(&testCase.pods, &versionedPods)
		if err != nil {
			t.Fatalf("error in versioning the pods: %s", testCase.desc, err)
		}
		data, err := testapi.Codec().Encode(versionedPods)
		if err != nil {
			t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err)
		}
		fakeHandler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: string(data),
		}
		testServer := httptest.NewServer(&fakeHandler)
		defer testServer.Close()
		ch := make(chan interface{}, 1)
		c := sourceURL{testServer.URL, hostname, ch, nil}
		if err := c.extractFromURL(); err != nil {
			t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
			continue
		}
		update := (<-ch).(kubelet.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, errors.NewAggregate(errs))
			}
		}
	}
}