diff --git a/pkg/api/conversion.go b/pkg/api/conversion.go index 98c3f85e849..6fc3c7d239f 100644 --- a/pkg/api/conversion.go +++ b/pkg/api/conversion.go @@ -32,6 +32,7 @@ func init() { out.Spec.Containers = in.Containers out.Spec.Volumes = in.Volumes out.Spec.RestartPolicy = in.RestartPolicy + out.Spec.DNSPolicy = in.DNSPolicy out.Name = in.ID out.UID = in.UUID // TODO(dchen1107): Move this conversion to pkg/api/v1beta[123]/conversion.go @@ -48,6 +49,7 @@ func init() { out.Containers = in.Spec.Containers out.Volumes = in.Spec.Volumes out.RestartPolicy = in.Spec.RestartPolicy + out.DNSPolicy = in.Spec.DNSPolicy out.Version = "v1beta2" out.ID = in.Name out.UUID = in.UID @@ -104,6 +106,7 @@ func init() { if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } + out.DNSPolicy = in.DNSPolicy out.Version = "v1beta2" return nil }, @@ -117,6 +120,7 @@ func init() { if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } + out.DNSPolicy = in.DNSPolicy return nil }, ) diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index c27c1713887..4731c48b886 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -370,8 +370,12 @@ func ValidatePod(pod *api.Pod) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} if len(pod.Name) == 0 { allErrs = append(allErrs, errs.NewFieldRequired("name", pod.Name)) + } else if !util.IsDNSSubdomain(pod.Name) { + allErrs = append(allErrs, errs.NewFieldInvalid("name", pod.Name, "")) } - if !util.IsDNSSubdomain(pod.Namespace) { + if len(pod.Namespace) == 0 { + allErrs = append(allErrs, errs.NewFieldRequired("namespace", pod.Namespace)) + } else if !util.IsDNSSubdomain(pod.Namespace) { allErrs = append(allErrs, errs.NewFieldInvalid("namespace", pod.Namespace, "")) } allErrs = append(allErrs, ValidatePodSpec(&pod.Spec).Prefix("spec")...) @@ -549,25 +553,20 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume) errs.ValidationErrorL } // ValidateBoundPod tests if required fields on a bound pod are set. -func ValidateBoundPod(pod *api.BoundPod) (errors []error) { - if !util.IsDNSSubdomain(pod.Name) { - errors = append(errors, errs.NewFieldInvalid("name", pod.Name, "")) +func ValidateBoundPod(pod *api.BoundPod) errs.ValidationErrorList { + allErrs := errs.ValidationErrorList{} + if len(pod.Name) == 0 { + allErrs = append(allErrs, errs.NewFieldRequired("name", pod.Name)) + } else if !util.IsDNSSubdomain(pod.Name) { + allErrs = append(allErrs, errs.NewFieldInvalid("name", pod.Name, "")) } - if !util.IsDNSSubdomain(pod.Namespace) { - errors = append(errors, errs.NewFieldInvalid("namespace", pod.Namespace, "")) + if len(pod.Name) == 0 { + allErrs = append(allErrs, errs.NewFieldRequired("namespace", pod.Namespace)) + } else if !util.IsDNSSubdomain(pod.Namespace) { + allErrs = append(allErrs, errs.NewFieldInvalid("namespace", pod.Namespace, "")) } - containerManifest := &api.ContainerManifest{ - Version: "v1beta2", - ID: pod.Name, - UUID: pod.UID, - Containers: pod.Spec.Containers, - Volumes: pod.Spec.Volumes, - RestartPolicy: pod.Spec.RestartPolicy, - } - if errs := ValidateManifest(containerManifest); len(errs) != 0 { - errors = append(errors, errs...) - } - return errors + allErrs = append(allErrs, ValidatePodSpec(&pod.Spec).Prefix("spec")...) + return allErrs } // ValidateMinion tests if required fields in the minion are set. diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index b4626f28815..a93ba27f48a 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -338,7 +338,22 @@ func TestValidateRestartPolicy(t *testing.T) { if noPolicySpecified.Always == nil { t.Errorf("expected Always policy specified") } +} +func TestValidateDNSPolicy(t *testing.T) { + successCases := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault, api.DNSPolicy("")} + for _, policy := range successCases { + if errs := validateDNSPolicy(&policy); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := []api.DNSPolicy{api.DNSPolicy("invalid")} + for _, policy := range errorCases { + if errs := validateDNSPolicy(&policy); len(errs) == 0 { + t.Errorf("expected failure for %v", policy) + } + } } func TestValidateManifest(t *testing.T) { @@ -404,59 +419,109 @@ func TestValidateManifest(t *testing.T) { } } -func TestValidatePod(t *testing.T) { - errs := ValidatePod(&api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "foo", Namespace: api.NamespaceDefault, - Labels: map[string]string{ - "foo": "bar", - }, +func TestValidatePodSpec(t *testing.T) { + successCases := []api.PodSpec{ + {}, // empty is valid, if not very useful */ + { // Populate basic fields, leave defaults for most. + Volumes: []api.Volume{{Name: "vol"}}, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicy{ - Always: &api.RestartPolicyAlways{}, + { // Populate all fields. + Volumes: []api.Volume{ + {Name: "vol"}, }, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, + DNSPolicy: api.DNSClusterFirst, + NodeSelector: map[string]string{ + "key": "value", + }, + Host: "foobar", }, - }) - if len(errs) != 0 { - t.Errorf("Unexpected non-zero error list: %#v", errs) } - errs = ValidatePod(&api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "foo", - Namespace: api.NamespaceDefault, - Labels: map[string]string{ - "foo": "bar", - }, - }, - Spec: api.PodSpec{}, - }) - if len(errs) != 0 { - t.Errorf("Unexpected non-zero error list: %#v", errs) + for i := range successCases { + if errs := ValidatePodSpec(&successCases[i]); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } } - errs = ValidatePodSpec(&api.PodSpec{ - RestartPolicy: api.RestartPolicy{ - Always: &api.RestartPolicyAlways{}, - Never: &api.RestartPolicyNever{}, + failureCases := map[string]api.PodSpec{ + "bad volume": { + Volumes: []api.Volume{{}}, + }, + "bad container": { + Containers: []api.Container{{}}, + }, + "bad DNS policy": { + DNSPolicy: api.DNSPolicy("invalid"), }, - }) - if len(errs) != 1 { - t.Errorf("Unexpected error list: %#v", errs) } - errs = ValidatePod(&api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "foo", - Namespace: api.NamespaceDefault, - Labels: map[string]string{ - "1/2/3/4/5": "bar", // invalid - "valid": "bar", // good + for k, v := range failureCases { + if errs := ValidatePodSpec(&v); len(errs) == 0 { + t.Errorf("expected failure for %q", k) + } + } + + defaultPod := api.PodSpec{} // all empty fields + if errs := ValidatePodSpec(&defaultPod); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + if util.AllPtrFieldsNil(defaultPod.RestartPolicy) { + t.Errorf("expected a default RestartPolicy") + } + if defaultPod.DNSPolicy == "" { + t.Errorf("expected a default DNSPolicy") + } +} + +func TestValidatePod(t *testing.T) { + successCases := []api.Pod{ + { // Mostly empty. + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"}, + }, + { // Basic fields. + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"}, + Spec: api.PodSpec{ + Volumes: []api.Volume{{Name: "vol"}}, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, }, }, - Spec: api.PodSpec{}, - }) - if len(errs) != 1 { - t.Errorf("Unexpected error list: %#v", errs) + { // Just about everything. + ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"}, + Spec: api.PodSpec{ + Volumes: []api.Volume{ + {Name: "vol"}, + }, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, + DNSPolicy: api.DNSClusterFirst, + NodeSelector: map[string]string{ + "key": "value", + }, + Host: "foobar", + }, + }, + } + for _, pod := range successCases { + if errs := ValidatePod(&pod); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := map[string]api.Pod{ + "bad name": {ObjectMeta: api.ObjectMeta{Name: "", Namespace: "ns"}}, + "bad namespace": {ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: ""}}, + "bad spec": { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"}, + Spec: api.PodSpec{ + Containers: []api.Container{{}}, + }, + }, + } + for k, v := range errorCases { + if errs := ValidatePod(&v); len(errs) == 0 { + t.Errorf("expected failure for %s", k) + } } } @@ -623,6 +688,57 @@ func TestValidatePodUpdate(t *testing.T) { } } +func TestValidateBoundPods(t *testing.T) { + successCases := []api.BoundPod{ + { // Mostly empty. + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"}, + }, + { // Basic fields. + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"}, + Spec: api.PodSpec{ + Volumes: []api.Volume{{Name: "vol"}}, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + }, + }, + { // Just about everything. + ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"}, + Spec: api.PodSpec{ + Volumes: []api.Volume{ + {Name: "vol"}, + }, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, + DNSPolicy: api.DNSClusterFirst, + NodeSelector: map[string]string{ + "key": "value", + }, + Host: "foobar", + }, + }, + } + for _, pod := range successCases { + if errs := ValidateBoundPod(&pod); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := map[string]api.Pod{ + "bad name": {ObjectMeta: api.ObjectMeta{Name: "", Namespace: "ns"}}, + "bad namespace": {ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: ""}}, + "bad spec": { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"}, + Spec: api.PodSpec{ + Containers: []api.Container{{}}, + }, + }, + } + for k, v := range errorCases { + if errs := ValidatePod(&v); len(errs) == 0 { + t.Errorf("expected failure for %s", k) + } + } +} + func TestValidateService(t *testing.T) { testCases := []struct { name string diff --git a/pkg/kubelet/config/config_test.go b/pkg/kubelet/config/config_test.go index c06f9e9e8ec..245008f52d0 100644 --- a/pkg/kubelet/config/config_test.go +++ b/pkg/kubelet/config/config_test.go @@ -59,6 +59,7 @@ func CreateValidPod(name, namespace, source string) api.BoundPod { }, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, + DNSPolicy: api.DNSClusterFirst, }, } } diff --git a/pkg/kubelet/config/http_test.go b/pkg/kubelet/config/http_test.go index 0592cd71ae6..a1c0b7d101b 100644 --- a/pkg/kubelet/config/http_test.go +++ b/pkg/kubelet/config/http_test.go @@ -132,6 +132,7 @@ func TestExtractFromHTTP(t *testing.T) { }, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, + DNSPolicy: api.DNSClusterFirst, }, }), },