Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update generic etcd to enable namespace scoped resources #2899

Merged
merged 2 commits into from
Dec 15, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 11 additions & 4 deletions pkg/registry/event/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand All @@ -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,
},
Expand Down
58 changes: 50 additions & 8 deletions pkg/registry/generic/etcd/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}
Expand All @@ -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)
}
Expand All @@ -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)
}

Expand All @@ -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
})
Expand Down
8 changes: 4 additions & 4 deletions pkg/registry/generic/etcd/etcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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)
Expand Down