diff --git a/pkg/route/api/allocator/allocator.go b/pkg/route/api/allocator/allocator.go new file mode 100644 index 000000000000..cbe71d894b20 --- /dev/null +++ b/pkg/route/api/allocator/allocator.go @@ -0,0 +1,34 @@ +package allocator + +import ( + "fmt" + + "code.google.com/p/go-uuid/uuid" + routeapi "github.com/openshift/origin/pkg/route/api" +) + +// This should be something we get from config but we would still need a +// default name if nothing's passed. The first pass uses the default name. +// Would be better if we could use "v3.openshift.app", someone bought that! +const defaultDNSSuffix = "v3.openshift.com" + +// Generate a host name for a route - using the service name, +// namespace (if provided) and the router shard dns suffix. +func Generate(route *routeapi.Route, shard *routeapi.RouterShard) string { + name := route.ServiceName + if len(name) == 0 { + name = uuid.NewUUID().String() + } + + if len(route.Namespace) <= 0 { + return fmt.Sprintf("%s.%s", name, shard.DNSSuffix) + } + + return fmt.Sprintf("%s-%s.%s", name, route.Namespace, shard.DNSSuffix) +} + +// Allocate a router shard for the given route. +// Placeholder for now ... returns the "global" router shard. +func Allocate(route *routeapi.Route) *routeapi.RouterShard { + return &routeapi.RouterShard{ShardName: "global", DNSSuffix: defaultDNSSuffix} +} diff --git a/pkg/route/api/allocator/allocator_test.go b/pkg/route/api/allocator/allocator_test.go new file mode 100644 index 000000000000..5ae0b921c1cf --- /dev/null +++ b/pkg/route/api/allocator/allocator_test.go @@ -0,0 +1,63 @@ +package allocator + +import ( + "testing" + + kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/openshift/origin/pkg/route/api" +) + +func TestAllocateRoute(t *testing.T) { + tests := []struct { + name string + route *api.Route + }{ + { + name: "No Name", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Namespace: "namespace", + }, + ServiceName: "service", + }, + }, + { + name: "No namespace", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + }, + ServiceName: "nonamespace", + }, + }, + { + name: "No service name", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + Namespace: "foo", + }, + }, + }, + { + name: "Valid route", + route: &api.Route{ + ObjectMeta: kapi.ObjectMeta{ + Name: "name", + Namespace: "foo", + }, + Host: "www.example.com", + ServiceName: "serviceName", + }, + }, + } + + for _, tc := range tests { + shard := Allocate(tc.route) + name := Generate(tc.route, shard) + + if len(name) <= 0 { + t.Errorf("Test case %s got %d length name.", tc.name, len(name)) + } + } +} diff --git a/pkg/route/api/types.go b/pkg/route/api/types.go index 94ec611a9e96..808bf43d6754 100644 --- a/pkg/route/api/types.go +++ b/pkg/route/api/types.go @@ -30,6 +30,20 @@ type RouteList struct { Items []Route `json:"items"` } +// RouterShard has information of a routing shard and is used to +// generate host names and routing table entries when a routing shard is +// allocated for a specific route. +// Caveat: This is WIP and will likely undergo modifications when sharding +// support is added. +type RouterShard struct { + // Shard name uniquely identifies a router shard in the "set" of + // routers used for routing traffic to the services. + ShardName string + + // The DNS suffix for the shard ala: shard-1.v3.openshift.com + DNSSuffix string +} + // TLSConfig defines config used to secure a route and provide termination type TLSConfig struct { // Termination indicates termination type. If termination type is not set, any termination config will be ignored diff --git a/pkg/route/registry/route/rest.go b/pkg/route/registry/route/rest.go index 4a25b09268f7..611d5a5c37d1 100644 --- a/pkg/route/registry/route/rest.go +++ b/pkg/route/registry/route/rest.go @@ -12,6 +12,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/openshift/origin/pkg/route/api" + "github.com/openshift/origin/pkg/route/api/allocator" "github.com/openshift/origin/pkg/route/api/validation" ) @@ -71,6 +72,13 @@ func (rs *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, er return nil, errors.NewConflict("route", route.Namespace, fmt.Errorf("Route.Namespace does not match the provided context")) } + // shards will be eventually allocated via a separate controller. + shard := allocator.Allocate(route) + + if len(route.Host) == 0 { + route.Host = allocator.Generate(route, shard) + } + if errs := validation.ValidateRoute(route); len(errs) > 0 { return nil, errors.NewInvalid("route", route.Name, errs) }