Exemplo n.º 1
0
func TestDecodeNumbers(t *testing.T) {

	// Start with a valid pod
	originalJSON := []byte(`{
		"kind":"Pod",
		"apiVersion":"v1",
		"metadata":{"name":"pod","namespace":"foo"},
		"spec":{
			"containers":[{"name":"container","image":"container"}],
			"activeDeadlineSeconds":9223372036854775807
		}
	}`)

	pod := &api.Pod{}

	// Decode with structured codec
	codec, err := testapi.GetCodecForObject(pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	err = codec.DecodeInto(originalJSON, pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// ensure pod is valid
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		t.Fatalf("pod should be valid: %v", errs)
	}

	// Round-trip with unstructured codec
	unstructuredObj, err := runtime.UnstructuredJSONScheme.Decode(originalJSON)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	roundtripJSON, err := json.Marshal(unstructuredObj.(*runtime.Unstructured).Object)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Decode with structured codec again
	pod2 := &api.Pod{}
	err = codec.DecodeInto(roundtripJSON, pod2)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// ensure pod is still valid
	if errs := validation.ValidatePod(pod2); len(errs) > 0 {
		t.Fatalf("pod should be valid: %v", errs)
	}
	// ensure round-trip preserved large integers
	if !reflect.DeepEqual(pod, pod2) {
		t.Fatalf("Expected\n\t%#v, got \n\t%#v", pod, pod2)
	}
}
Exemplo n.º 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
}
Exemplo n.º 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
}
Exemplo n.º 4
0
func TestReadPodsFromFileExistAlready(t *testing.T) {
	hostname := types.NodeName("random-test-hostname")
	var testCases = getTestCases(hostname)

	for _, testCase := range testCases {
		func() {
			dirName, err := utiltesting.MkTmpdir("file-test")
			if err != nil {
				t.Fatalf("unable to create temp dir: %v", err)
			}
			defer os.RemoveAll(dirName)
			file := testCase.writeToFile(dirName, "test_pod_config", t)

			ch := make(chan interface{})
			NewSourceFile(file, hostname, time.Millisecond, ch)
			select {
			case got := <-ch:
				update := got.(kubetypes.PodUpdate)
				for _, pod := range update.Pods {
					if errs := validation.ValidatePod(pod); len(errs) > 0 {
						t.Fatalf("%s: Invalid pod %#v, %#v", testCase.desc, pod, errs)
					}
				}
				if !api.Semantic.DeepEqual(testCase.expected, update) {
					t.Fatalf("%s: Expected %#v, Got %#v", testCase.desc, testCase.expected, update)
				}
			case <-time.After(wait.ForeverTestTimeout):
				t.Fatalf("%s: Expected update, timeout instead", testCase.desc)
			}
		}()
	}
}
Exemplo n.º 5
0
func expectUpdate(t *testing.T, ch chan interface{}, testCase *testCase) {
	timer := time.After(5 * time.Second)
	for {
		select {
		case got := <-ch:
			update := got.(kubetypes.PodUpdate)
			for _, pod := range update.Pods {
				// TODO: remove the conversion when validation is performed on versioned objects.
				internalPod := &api.Pod{}
				if err := v1.Convert_v1_Pod_To_api_Pod(pod, internalPod, nil); err != nil {
					t.Fatalf("%s: Cannot convert pod %#v, %#v", testCase.desc, pod, err)
				}
				if errs := validation.ValidatePod(internalPod); len(errs) > 0 {
					t.Fatalf("%s: Invalid pod %#v, %#v", testCase.desc, internalPod, errs)
				}
			}

			if !api.Semantic.DeepEqual(testCase.expected, update) {
				t.Fatalf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
			}
			return
		case <-timer:
			t.Fatalf("%s: Expected update, timeout instead", testCase.desc)
		}
	}
}
Exemplo n.º 6
0
func validateContainer(c kube.Container) error {
	validMeta := kube.ObjectMeta{
		Name:      "valid",
		Namespace: "object",
	}

	pod := kube.Pod{
		ObjectMeta: validMeta,
		Spec: kube.PodSpec{
			Containers:    []kube.Container{c},
			RestartPolicy: kube.RestartPolicyAlways,
			DNSPolicy:     kube.DNSClusterFirst,
		},
	}

	// fake volumes to allow validation
	for _, mount := range c.VolumeMounts {
		volume := kube.Volume{
			Name:         mount.Name,
			VolumeSource: kube.VolumeSource{EmptyDir: &kube.EmptyDirVolumeSource{}},
		}
		pod.Spec.Volumes = append(pod.Spec.Volumes, volume)
	}

	errList := validation.ValidatePod(&pod)

	// Remove error for missing image field
	return errList.Filter(func(e error) bool {
		return e.Error() == NoImageErrStr
	}).ToAggregate()
}
Exemplo n.º 7
0
func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods v1.PodList, err error) {
	obj, err := runtime.Decode(api.Codecs.UniversalDecoder(), data)
	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
		}
	}
	v1Pods := &v1.PodList{}
	if err := v1.Convert_api_PodList_To_v1_PodList(newPods, v1Pods, nil); err != nil {
		return true, pods, err
	}
	return true, *v1Pods, err
}
Exemplo n.º 8
0
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
}
Exemplo n.º 9
0
func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) {
	names := sets.String{}
	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
}
Exemplo n.º 10
0
func TestCompatibility_v1_Pod(t *testing.T) {
	// Test "spec.serviceAccount" -> "spec.serviceAccountName"
	expectedServiceAccount := "my-service-account"

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

	t.Log("Testing 1.0.0 v1 migration added in PR #3592")
	testCompatibility(
		t, "v1", input,
		func(obj runtime.Object) field.ErrorList {
			return validation.ValidatePod(obj.(*api.Pod))
		},
		map[string]string{
			"spec.serviceAccount":     expectedServiceAccount,
			"spec.serviceAccountName": expectedServiceAccount,
		},
	)
}
Exemplo n.º 11
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)
		}
	}

}
Exemplo n.º 12
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,
		},
	)
}
Exemplo n.º 13
0
func validatePod(pod *kube.Pod, ignoreContainers bool) error {
	errList := validation.ValidatePod(pod)

	// remove error for no containers if requested
	if ignoreContainers {
		errList = errList.Filter(func(e error) bool {
			return e.Error() == "spec.containers: Required value"
		})
	}

	meta := pod.GetObjectMeta()
	if len(meta.GetName()) == 0 && len(meta.GetGenerateName()) > 0 {
		errList = errList.Filter(func(e error) bool {
			return e.Error() == "metadata.name: Required value: name or generateName is required"
		})
	}

	return errList.ToAggregate()
}
Exemplo n.º 14
0
func expectUpdate(t *testing.T, ch chan interface{}, testCase *testCase) {
	timer := time.After(5 * time.Second)
	for {
		select {
		case got := <-ch:
			update := got.(kubetypes.PodUpdate)
			for _, pod := range update.Pods {
				if errs := validation.ValidatePod(pod); len(errs) > 0 {
					t.Fatalf("%s: Invalid pod %#v, %#v", testCase.desc, pod, errs)
				}
			}

			if !api.Semantic.DeepEqual(testCase.expected, update) {
				t.Fatalf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
			}
			return
		case <-timer:
			t.Fatalf("%s: Expected update, timeout instead", testCase.desc)
		}
	}
}
Exemplo n.º 15
0
// tryDecodeSinglePod was copied from pkg/kubelet/config/common.go v1.0.5
func tryDecodeSinglePod(data []byte) (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 := runtime.Decode(api.Codecs.UniversalDecoder(), 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)
	if errs := validation.ValidatePod(newPod); len(errs) > 0 {
		err = fmt.Errorf("invalid pod: %v", errs)
		return true, pod, err
	}
	return true, newPod, nil
}
Exemplo n.º 16
0
// Validate validates a new pod.
func (podStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList {
	pod := obj.(*api.Pod)
	return validation.ValidatePod(pod)
}
Exemplo n.º 17
0
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{},
				},
			},
			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",
						}},
					},
				}),
		},
		{
			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{},
						},
					},
					{
						ObjectMeta: api.ObjectMeta{
							Name: "bar",
							UID:  "222",
						},
						Spec: api.PodSpec{
							NodeName:        hostname,
							Containers:      []api.Container{{Name: "2", Image: "bar", ImagePullPolicy: ""}},
							SecurityContext: &api.PodSecurityContext{},
						},
					},
				},
			},
			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",
						}},
					},
				},
				&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",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "IfNotPresent",
						}},
					},
				}),
		},
	}

	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 := testapi.Default.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, http.Header{}, hostname, ch, nil, 0}
		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())
			}
		}
	}
}
Exemplo n.º 18
0
// ValidateUpdate is the default update validation for an end user.
func (podStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList {
	errorList := validation.ValidatePod(obj.(*api.Pod))
	return append(errorList, validation.ValidatePodUpdate(obj.(*api.Pod), old.(*api.Pod))...)
}
Exemplo n.º 19
0
// ValidateUpdate is the default update validation for an end user.
func (podStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList {
	errorList := validation.ValidatePod(obj.(*api.Pod))
	return append(errorList, validation.ValidatePodUpdate(obj.(*api.Pod), old.(*api.Pod))...)
}
Exemplo n.º 20
0
func validateObject(obj runtime.Object) (errors field.ErrorList) {
	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)
	case *api.Endpoints:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateEndpoints(t)
	case *api.Namespace:
		errors = validation.ValidateNamespace(t)
	case *api.Secret:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateSecret(t)
	case *api.LimitRange:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateLimitRange(t)
	case *api.ResourceQuota:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateResourceQuota(t)
	case *extensions.Deployment:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateDeployment(t)
	case *extensions.Job:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		// Job needs generateSelector called before validation, and job.Validate does this.
		// See: https://github.com/kubernetes/kubernetes/issues/20951#issuecomment-187787040
		t.ObjectMeta.UID = types.UID("fakeuid")
		errors = job.Strategy.Validate(nil, t)
	case *extensions.Ingress:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateIngress(t)
	case *extensions.DaemonSet:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateDaemonSet(t)
	default:
		errors = field.ErrorList{}
		errors = append(errors, field.InternalError(field.NewPath(""), fmt.Errorf("no validation defined for %#v", obj)))
	}
	return errors
}
Exemplo n.º 21
0
// Validate validates a new pod.
func (podStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
	pod := obj.(*api.Pod)
	return validation.ValidatePod(pod)
}
Exemplo n.º 22
0
func TestReadPodsFromFile(t *testing.T) {
	nodeName := "random-test-hostname"
	grace := int64(30)
	var testCases = []struct {
		desc     string
		pod      runtime.Object
		expected kubetypes.PodUpdate
	}{
		{
			desc: "Simple pod",
			pod: &api.Pod{
				TypeMeta: unversioned.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()}},
					SecurityContext: &api.PodSecurityContext{},
				},
				Status: api.PodStatus{
					Phase: api.PodPending,
				},
			},
			expected: CreatePodUpdate(kubetypes.SET, kubetypes.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:        "test-" + nodeName,
					UID:         "12345",
					Namespace:   "mynamespace",
					Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "12345"},
					SelfLink:    getSelfLink("test-"+nodeName, "mynamespace"),
				},
				Spec: api.PodSpec{
					NodeName:                      nodeName,
					RestartPolicy:                 api.RestartPolicyAlways,
					DNSPolicy:                     api.DNSClusterFirst,
					TerminationGracePeriodSeconds: &grace,
					Containers: []api.Container{{
						Name:  "image",
						Image: "test/image",
						TerminationMessagePath: "/dev/termination-log",
						ImagePullPolicy:        "Always",
						SecurityContext:        securitycontext.ValidSecurityContextWithContainerDefaults()}},
					SecurityContext: &api.PodSecurityContext{},
				},
				Status: api.PodStatus{
					Phase: api.PodPending,
				},
			}),
		},
	}

	for _, testCase := range testCases {
		func() {
			var versionedPod runtime.Object
			err := testapi.Default.Converter().Convert(&testCase.pod, &versionedPod, nil)
			if err != nil {
				t.Fatalf("%s: error in versioning the pod: %v", testCase.desc, err)
			}
			fileContents, err := runtime.Encode(testapi.Default.Codec(), 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(), types.NodeName(nodeName), time.Millisecond, ch)
			select {
			case got := <-ch:
				update := got.(kubetypes.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(wait.ForeverTestTimeout):
				t.Errorf("%s: Expected update, timeout instead", testCase.desc)
			}
		}()
	}
}
Exemplo n.º 23
0
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)
	case *api.Endpoints:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateEndpoints(t)
	case *api.Namespace:
		errors = validation.ValidateNamespace(t)
	case *api.Secret:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateSecret(t)
	case *api.LimitRange:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateLimitRange(t)
	case *api.ResourceQuota:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateResourceQuota(t)
	default:
		return []error{fmt.Errorf("no validation defined for %#v", obj)}
	}
	return errors
}
Exemplo n.º 24
0
// Validate validates a new pod.
func (podStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
	glog.Info("pkg/registry/pod/strategy.go #Validate")
	pod := obj.(*api.Pod)
	return validation.ValidatePod(pod)
}
Exemplo n.º 25
0
func validateObject(obj runtime.Object) (errors field.ErrorList) {
	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)
	case *api.Endpoints:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateEndpoints(t)
	case *api.Namespace:
		errors = validation.ValidateNamespace(t)
	case *api.Secret:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateSecret(t)
	case *api.LimitRange:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateLimitRange(t)
	case *api.ResourceQuota:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = validation.ValidateResourceQuota(t)
	case *extensions.Deployment:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateDeployment(t)
	case *extensions.Job:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateJob(t)
	case *extensions.Ingress:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateIngress(t)
	case *extensions.DaemonSet:
		if t.Namespace == "" {
			t.Namespace = api.NamespaceDefault
		}
		errors = expvalidation.ValidateDaemonSet(t)
	default:
		return field.ErrorList{field.InternalError(field.NewPath(""), fmt.Errorf("no validation defined for %#v", obj))}
	}
	return errors
}
Exemplo n.º 26
0
func TestDecodeNumbers(t *testing.T) {

	// Start with a valid pod
	originalJSON := []byte(`{
		"kind":"Pod",
		"apiVersion":"v1",
		"metadata":{"name":"pod","namespace":"foo"},
		"spec":{
			"containers":[{"name":"container","image":"container"}],
			"activeDeadlineSeconds":1000030003
		}
	}`)

	pod := &api.Pod{}

	// Decode with structured codec
	codec, err := testapi.GetCodecForObject(pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	err = runtime.DecodeInto(codec, originalJSON, pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// ensure pod is valid
	if errs := validation.ValidatePod(pod); len(errs) > 0 {
		t.Fatalf("pod should be valid: %v", errs)
	}

	// Round-trip with unstructured codec
	unstructuredObj, err := runtime.Decode(runtime.UnstructuredJSONScheme, originalJSON)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	roundtripJSON, err := runtime.Encode(runtime.UnstructuredJSONScheme, unstructuredObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Make sure we serialize back out in int form
	if !strings.Contains(string(roundtripJSON), `"activeDeadlineSeconds":1000030003`) {
		t.Errorf("Expected %s, got %s", `"activeDeadlineSeconds":1000030003`, string(roundtripJSON))
	}

	// Decode with structured codec again
	obj2, err := runtime.Decode(codec, roundtripJSON)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// ensure pod is still valid
	pod2, ok := obj2.(*api.Pod)
	if !ok {
		t.Fatalf("expected an *api.Pod, got %#v", obj2)
	}
	if errs := validation.ValidatePod(pod2); len(errs) > 0 {
		t.Fatalf("pod should be valid: %v", errs)
	}
	// ensure round-trip preserved large integers
	if !reflect.DeepEqual(pod, pod2) {
		t.Fatalf("Expected\n\t%#v, got \n\t%#v", pod, pod2)
	}
}
Exemplo n.º 27
0
// TestCompatibility_v1_VolumeSource tests that the metadata field in volume
// sources gets properly round-tripped
func TestCompatibility_v1_VolumeSource(t *testing.T) {
	// Test volume source compatibility
	path := "test/volume/source/compat"

	metadata := []byte(fmt.Sprintf(`
{
	"kind":"Pod",
	"apiVersion":"v1",
	"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
	"spec": {
		"containers":[{
			"name":"my-container-name",
			"image":"my-container-image",
			"ports":[{"containerPort":1,"protocol":"TCP"}]
		}],
		"volumes":[{
			"name":"a-metadata-volume",
			"metadata":{"items":[{"name":"%s","fieldRef":{"apiVersion":"v1","fieldPath":"metadata.name"}}]}
		}]
	}
}
`, path))

	downward := []byte(fmt.Sprintf(`
{
	"kind":"Pod",
	"apiVersion":"v1",
	"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
	"spec": {
		"containers":[{
			"name":"my-container-name",
			"image":"my-container-image",
			"ports":[{"containerPort":1,"protocol":"TCP"}]
		}],
		"volumes":[{
			"name":"a-downwardapi-volume",
			"downwardAPI":{"items":[{"path":"%s","fieldRef":{"apiVersion":"v1","fieldPath":"metadata.name"}}]}
		}]
	}
}
`, path))

	t.Log("Testing 1.0.6 v1 migration added in PR #4663")
	testCompatibility(
		t, "v1", metadata,
		func(obj runtime.Object) field.ErrorList {
			return validation.ValidatePod(obj.(*api.Pod))
		},
		map[string]string{
			"spec.volumes[0].metadata.items[0].name":    path,
			"spec.volumes[0].downwardAPI.items[0].path": path,
		},
	)
	testCompatibility(
		t, "v1", downward,
		func(obj runtime.Object) field.ErrorList {
			return validation.ValidatePod(obj.(*api.Pod))
		},
		map[string]string{
			"spec.volumes[0].metadata.items[0].name":    path,
			"spec.volumes[0].downwardAPI.items[0].path": path,
		},
	)
}