diff --git a/pkg/registry/event/registry.go b/pkg/registry/event/registry.go index f36d0163e5b..fa207bd274d 100644 --- a/pkg/registry/event/registry.go +++ b/pkg/registry/event/registry.go @@ -35,7 +35,11 @@ type registry struct { // Create stores the object with a ttl, so that events don't stay in the system forever. func (r registry) Create(ctx api.Context, id string, obj runtime.Object) error { - err := r.Etcd.Helper.CreateObj(r.Etcd.KeyFunc(id), obj, r.ttl) + key, err := r.Etcd.KeyFunc(ctx, id) + if err != nil { + return err + } + err = r.Etcd.Helper.CreateObj(key, obj, r.ttl) return etcderr.InterpretCreateError(err, r.Etcd.EndpointName, id) } @@ -47,9 +51,12 @@ func NewEtcdRegistry(h tools.EtcdHelper, ttl uint64) generic.Registry { NewFunc: func() runtime.Object { return &api.Event{} }, NewListFunc: func() runtime.Object { return &api.EventList{} }, EndpointName: "events", - KeyRoot: "/registry/events", - KeyFunc: func(id string) string { - return path.Join("/registry/events", id) + KeyRootFunc: func(ctx api.Context) string { + return "/registry/events" + }, + KeyFunc: func(ctx api.Context, id string) (string, error) { + // TODO - we need to store this in a namespace relative path + return path.Join("/registry/events", id), nil }, Helper: h, }, diff --git a/pkg/registry/generic/etcd/etcd.go b/pkg/registry/generic/etcd/etcd.go index 0d27246e685..8dfda348fc9 100644 --- a/pkg/registry/generic/etcd/etcd.go +++ b/pkg/registry/generic/etcd/etcd.go @@ -18,6 +18,7 @@ package etcd import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + kubeerr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -41,19 +42,44 @@ type Etcd struct { EndpointName string // Used for listing/watching; should not include trailing "/" - KeyRoot string + KeyRootFunc func(ctx api.Context) string // Called for Create/Update/Get/Delete - KeyFunc func(id string) string + KeyFunc func(ctx api.Context, id string) (string, error) // Used for all etcd access functions Helper tools.EtcdHelper } +// NamespaceKeyRootFunc is the default function for constructing etcd paths to resource directories enforcing namespace rules. +func NamespaceKeyRootFunc(ctx api.Context, prefix string) string { + key := prefix + ns, ok := api.NamespaceFrom(ctx) + if ok && len(ns) > 0 { + key = key + "/" + ns + } + return key +} + +// NamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. +// If no namespace is on context, it errors. +func NamespaceKeyFunc(ctx api.Context, prefix string, id string) (string, error) { + key := NamespaceKeyRootFunc(ctx, prefix) + ns, ok := api.NamespaceFrom(ctx) + if !ok || len(ns) == 0 { + return "", kubeerr.NewBadRequest("Namespace parameter required.") + } + if len(id) == 0 { + return "", kubeerr.NewBadRequest("Namespace parameter required.") + } + key = key + "/" + id + return key, nil +} + // List returns a list of all the items matching m. func (e *Etcd) List(ctx api.Context, m generic.Matcher) (runtime.Object, error) { list := e.NewListFunc() - err := e.Helper.ExtractToList(e.KeyRoot, list) + err := e.Helper.ExtractToList(e.KeyRootFunc(ctx), list) if err != nil { return nil, err } @@ -62,21 +88,33 @@ func (e *Etcd) List(ctx api.Context, m generic.Matcher) (runtime.Object, error) // Create inserts a new item. func (e *Etcd) Create(ctx api.Context, id string, obj runtime.Object) error { - err := e.Helper.CreateObj(e.KeyFunc(id), obj, 0) + key, err := e.KeyFunc(ctx, id) + if err != nil { + return err + } + err = e.Helper.CreateObj(key, obj, 0) return etcderr.InterpretCreateError(err, e.EndpointName, id) } // Update updates the item. func (e *Etcd) Update(ctx api.Context, id string, obj runtime.Object) error { + key, err := e.KeyFunc(ctx, id) + if err != nil { + return err + } // TODO: verify that SetObj checks ResourceVersion before succeeding. - err := e.Helper.SetObj(e.KeyFunc(id), obj) + err = e.Helper.SetObj(key, obj) return etcderr.InterpretUpdateError(err, e.EndpointName, id) } // Get retrieves the item from etcd. func (e *Etcd) Get(ctx api.Context, id string) (runtime.Object, error) { obj := e.NewFunc() - err := e.Helper.ExtractObj(e.KeyFunc(id), obj, false) + key, err := e.KeyFunc(ctx, id) + if err != nil { + return nil, err + } + err = e.Helper.ExtractObj(key, obj, false) if err != nil { return nil, etcderr.InterpretGetError(err, e.EndpointName, id) } @@ -85,7 +123,11 @@ func (e *Etcd) Get(ctx api.Context, id string) (runtime.Object, error) { // Delete removes the item from etcd. func (e *Etcd) Delete(ctx api.Context, id string) error { - err := e.Helper.Delete(e.KeyFunc(id), false) + key, err := e.KeyFunc(ctx, id) + if err != nil { + return err + } + err = e.Helper.Delete(key, false) return etcderr.InterpretDeleteError(err, e.EndpointName, id) } @@ -96,7 +138,7 @@ func (e *Etcd) Watch(ctx api.Context, m generic.Matcher, resourceVersion string) if err != nil { return nil, err } - return e.Helper.WatchList(e.KeyRoot, version, func(obj runtime.Object) bool { + return e.Helper.WatchList(e.KeyRootFunc(ctx), version, func(obj runtime.Object) bool { matches, err := m.Matches(obj) return err == nil && matches }) diff --git a/pkg/registry/generic/etcd/etcd_test.go b/pkg/registry/generic/etcd/etcd_test.go index 0cf216fb4e2..1d14e3302dc 100644 --- a/pkg/registry/generic/etcd/etcd_test.go +++ b/pkg/registry/generic/etcd/etcd_test.go @@ -41,9 +41,9 @@ func NewTestGenericEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, *Etcd) { NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, EndpointName: "pods", - KeyRoot: "/registry/pods", - KeyFunc: func(id string) string { - return path.Join("/registry/pods", id) + KeyRootFunc: func(ctx api.Context) string { return "/registry/pods" }, + KeyFunc: func(ctx api.Context, id string) (string, error) { + return path.Join("/registry/pods", id), nil }, Helper: h, } @@ -139,7 +139,7 @@ func TestEtcdList(t *testing.T) { for name, item := range table { fakeClient, registry := NewTestGenericEtcdRegistry(t) - fakeClient.Data[registry.KeyRoot] = item.in + fakeClient.Data[registry.KeyRootFunc(api.NewContext())] = item.in list, err := registry.List(api.NewContext(), item.m) if e, a := item.succeed, err == nil; e != a { t.Errorf("%v: expected %v, got %v", name, e, a)