diff --git a/pkg/route/api/validation/validation.go b/pkg/route/api/validation/validation.go index 1a88f19432e2..2aac4bea4dd2 100644 --- a/pkg/route/api/validation/validation.go +++ b/pkg/route/api/validation/validation.go @@ -2,6 +2,8 @@ package validation import ( errs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + kval "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" routeapi "github.com/openshift/origin/pkg/route/api" ) @@ -10,9 +12,16 @@ import ( func ValidateRoute(route *routeapi.Route) errs.ValidationErrorList { result := errs.ValidationErrorList{} - if len(route.Host) == 0 { - result = append(result, errs.NewFieldRequired("host", "")) + //ensure meta is set properly + result = append(result, kval.ValidateObjectMeta(&route.ObjectMeta, true, kval.ValidatePodName)...) + + //host is not required but if it is set ensure it meets DNS requirements + if len(route.Host) > 0 { + if !util.IsDNSSubdomain(route.Host) { + result = append(result, errs.NewFieldInvalid("host", route.Host, "Host must conform to DNS 952 subdomain conventions")) + } } + if len(route.ServiceName) == 0 { result = append(result, errs.NewFieldRequired("serviceName", "")) } diff --git a/pkg/route/api/validation/validation_test.go b/pkg/route/api/validation/validation_test.go index a544005e5675..b554525a161f 100644 --- a/pkg/route/api/validation/validation_test.go +++ b/pkg/route/api/validation/validation_test.go @@ -3,9 +3,97 @@ package validation import ( "testing" + kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/openshift/origin/pkg/route/api" ) +// TestValidateRouteBad ensures not specifying a required field results in error and a fully specified +// route passes successfully +func TestValidateRoute(t *testing.T) { + tests := []struct { + name string + route *api.Route + expectedErrors int + }{ + { + name: "No Name", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Namespace: "foo", + }, + Host: "host", + ServiceName: "serviceName", + }, + expectedErrors: 1, + }, + { + name: "No namespace", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + }, + Host: "host", + ServiceName: "serviceName", + }, + expectedErrors: 1, + }, + { + name: "No host", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + Namespace: "foo", + }, + ServiceName: "serviceName", + }, + expectedErrors: 0, + }, + { + name: "Invalid DNS 952 host", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + Namespace: "foo", + }, + Host: "**", + ServiceName: "serviceName", + }, + expectedErrors: 1, + }, + { + name: "No service name", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + Namespace: "foo", + }, + Host: "host", + }, + expectedErrors: 1, + }, + { + name: "Valid route", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + Namespace: "foo", + }, + Host: "www.example.com", + ServiceName: "serviceName", + }, + expectedErrors: 0, + }, + } + + for _, tc := range tests { + errs := ValidateRoute(tc.route) + + if len(errs) != tc.expectedErrors { + t.Errorf("Test case %s expected %d error(s), got %d. %v", tc.name, tc.expectedErrors, len(errs), errs) + } + } +} + func TestValidateTLSNoTLSTermOk(t *testing.T) { errs := validateTLS(&api.TLSConfig{ Termination: "", diff --git a/pkg/template/template_test.go b/pkg/template/template_test.go index 4e724fe07cda..16e51eab90d4 100644 --- a/pkg/template/template_test.go +++ b/pkg/template/template_test.go @@ -129,5 +129,5 @@ func ExampleProcessTemplateParameters() { } // Output: // - //{"kind":"Config","apiVersion":"v1beta1","metadata":{"creationTimestamp":null},"items":[{"kind":"Route","apiVersion":"v1beta1","metadata":{"creationTimestamp":null},"host":"guestbook.example.com","serviceName":"frontend-service"},{"kind":"Service","id":"frontend-service","creationTimestamp":null,"apiVersion":"v1beta1","port":5432,"protocol":"TCP","selector":{"name":"frontend-service"},"containerPort":0,"sessionAffinity":"None"},{"kind":"Service","id":"redis-master","creationTimestamp":null,"apiVersion":"v1beta1","port":10000,"protocol":"TCP","selector":{"name":"redis-master"},"containerPort":0,"sessionAffinity":"None"},{"kind":"Service","id":"redis-slave","creationTimestamp":null,"apiVersion":"v1beta1","port":10001,"protocol":"TCP","selector":{"name":"redis-slave"},"containerPort":0,"sessionAffinity":"None"},{"kind":"Pod","id":"redis-master","creationTimestamp":null,"apiVersion":"v1beta1","labels":{"name":"redis-master"},"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"master","image":"dockerfile/redis","ports":[{"containerPort":6379,"protocol":"TCP"}],"env":[{"name":"REDIS_PASSWORD","key":"REDIS_PASSWORD","value":"P8vxbV4C"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"currentState":{"manifest":{"version":"","id":"","volumes":null,"containers":null,"restartPolicy":{}}}},{"kind":"ReplicationController","id":"guestbook","creationTimestamp":null,"apiVersion":"v1beta1","desiredState":{"replicas":3,"replicaSelector":{"name":"frontend-service"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"php-redis","image":"brendanburns/php-redis","ports":[{"hostPort":8000,"containerPort":80,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminQ3H"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"dwNJiJwW"},{"name":"REDIS_PASSWORD","key":"REDIS_PASSWORD","value":"P8vxbV4C"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend-service"}}},"currentState":{"replicas":0,"podTemplate":{"desiredState":{"manifest":{"version":"","id":"","volumes":null,"containers":null,"restartPolicy":{}}}}}},{"kind":"ReplicationController","id":"redis-slave","creationTimestamp":null,"apiVersion":"v1beta1","desiredState":{"replicas":2,"replicaSelector":{"name":"redis-slave"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"slave","image":"brendanburns/redis-slave","ports":[{"hostPort":6380,"containerPort":6379,"protocol":"TCP"}],"env":[{"name":"REDIS_PASSWORD","key":"REDIS_PASSWORD","value":"P8vxbV4C"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"redis-slave"}}},"currentState":{"replicas":0,"podTemplate":{"desiredState":{"manifest":{"version":"","id":"","volumes":null,"containers":null,"restartPolicy":{}}}}}}]} + //{"kind":"Config","apiVersion":"v1beta1","metadata":{"creationTimestamp":null},"items":[{"kind":"Route","apiVersion":"v1beta1","metadata":{"name":"frontend-route","creationTimestamp":null},"host":"guestbook.example.com","serviceName":"frontend-service"},{"kind":"Service","id":"frontend-service","creationTimestamp":null,"apiVersion":"v1beta1","port":5432,"protocol":"TCP","selector":{"name":"frontend-service"},"containerPort":0,"sessionAffinity":"None"},{"kind":"Service","id":"redis-master","creationTimestamp":null,"apiVersion":"v1beta1","port":10000,"protocol":"TCP","selector":{"name":"redis-master"},"containerPort":0,"sessionAffinity":"None"},{"kind":"Service","id":"redis-slave","creationTimestamp":null,"apiVersion":"v1beta1","port":10001,"protocol":"TCP","selector":{"name":"redis-slave"},"containerPort":0,"sessionAffinity":"None"},{"kind":"Pod","id":"redis-master","creationTimestamp":null,"apiVersion":"v1beta1","labels":{"name":"redis-master"},"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"master","image":"dockerfile/redis","ports":[{"containerPort":6379,"protocol":"TCP"}],"env":[{"name":"REDIS_PASSWORD","key":"REDIS_PASSWORD","value":"P8vxbV4C"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"currentState":{"manifest":{"version":"","id":"","volumes":null,"containers":null,"restartPolicy":{}}}},{"kind":"ReplicationController","id":"guestbook","creationTimestamp":null,"apiVersion":"v1beta1","desiredState":{"replicas":3,"replicaSelector":{"name":"frontend-service"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"php-redis","image":"brendanburns/php-redis","ports":[{"hostPort":8000,"containerPort":80,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminQ3H"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"dwNJiJwW"},{"name":"REDIS_PASSWORD","key":"REDIS_PASSWORD","value":"P8vxbV4C"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend-service"}}},"currentState":{"replicas":0,"podTemplate":{"desiredState":{"manifest":{"version":"","id":"","volumes":null,"containers":null,"restartPolicy":{}}}}}},{"kind":"ReplicationController","id":"redis-slave","creationTimestamp":null,"apiVersion":"v1beta1","desiredState":{"replicas":2,"replicaSelector":{"name":"redis-slave"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"slave","image":"brendanburns/redis-slave","ports":[{"hostPort":6380,"containerPort":6379,"protocol":"TCP"}],"env":[{"name":"REDIS_PASSWORD","key":"REDIS_PASSWORD","value":"P8vxbV4C"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"redis-slave"}}},"currentState":{"replicas":0,"podTemplate":{"desiredState":{"manifest":{"version":"","id":"","volumes":null,"containers":null,"restartPolicy":{}}}}}}]} } diff --git a/test/templates/fixtures/guestbook.json b/test/templates/fixtures/guestbook.json index 0ec92b033cb6..46d61f5071e8 100644 --- a/test/templates/fixtures/guestbook.json +++ b/test/templates/fixtures/guestbook.json @@ -30,6 +30,9 @@ "items": [ { "id": "frontend-route", + "metadata": { + "name": "frontend-route" + }, "kind": "Route", "apiVersion": "v1beta1", "host": "guestbook.example.com",