Commit a7623ca6 authored by Karl Beecher's avatar Karl Beecher

Adds ability to define a prefix for etcd paths

The API server can be supplied (via a command line flag) with a custom prefix that is prepended to etcd resources paths. Refs: #3476
parent 2532fe56
......@@ -51,6 +51,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait"
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/empty_dir"
......@@ -160,7 +161,7 @@ func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (st
cl := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: apiVersion})
helper, err := master.NewEtcdHelper(etcdClient, "")
helper, err := master.NewEtcdHelper(etcdClient, "", etcdtest.PathPrefix())
if err != nil {
glog.Fatalf("Unable to get etcd helper: %v", err)
}
......
......@@ -71,6 +71,7 @@ type APIServer struct {
AdmissionControlConfigFile string
EtcdServerList util.StringList
EtcdConfigFile string
EtcdPathPrefix string
CorsAllowedOriginList util.StringList
AllowPrivileged bool
PortalNet util.IPNet // TODO: make this a list
......@@ -98,6 +99,7 @@ func NewAPIServer() *APIServer {
EventTTL: 1 * time.Hour,
AuthorizationMode: "AlwaysAllow",
AdmissionControl: "AlwaysAdmit",
EtcdPathPrefix: master.DefaultEtcdPathPrefix,
EnableLogsSupport: true,
MasterServiceNamespace: api.NamespaceDefault,
ClusterName: "kubernetes",
......@@ -161,6 +163,7 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.AdmissionControlConfigFile, "admission_control_config_file", s.AdmissionControlConfigFile, "File with admission control configuration.")
fs.Var(&s.EtcdServerList, "etcd_servers", "List of etcd servers to watch (http://ip:port), comma separated. Mutually exclusive with -etcd_config")
fs.StringVar(&s.EtcdConfigFile, "etcd_config", s.EtcdConfigFile, "The config file for the etcd client. Mutually exclusive with -etcd_servers.")
fs.StringVar(&s.EtcdPathPrefix, "etcd_prefix", s.EtcdPathPrefix, "The prefix for all resource paths in etcd.")
fs.Var(&s.CorsAllowedOriginList, "cors_allowed_origins", "List of allowed origins for CORS, comma separated. An allowed origin can be a regular expression to support subdomain matching. If this list is empty CORS will not be enabled.")
fs.BoolVar(&s.AllowPrivileged, "allow_privileged", s.AllowPrivileged, "If true, allow privileged containers.")
fs.Var(&s.PortalNet, "portal_net", "A CIDR notation IP range from which to assign portal IPs. This must not overlap with any IP ranges assigned to nodes for pods.")
......@@ -181,7 +184,7 @@ func (s *APIServer) verifyPortalFlags() {
}
}
func newEtcd(etcdConfigFile string, etcdServerList util.StringList, storageVersion string) (helper tools.EtcdHelper, err error) {
func newEtcd(etcdConfigFile string, etcdServerList util.StringList, storageVersion string, pathPrefix string) (helper tools.EtcdHelper, err error) {
var client tools.EtcdGetSet
if etcdConfigFile != "" {
client, err = etcd.NewClientFromFile(etcdConfigFile)
......@@ -192,7 +195,7 @@ func newEtcd(etcdConfigFile string, etcdServerList util.StringList, storageVersi
client = etcd.NewClient(etcdServerList)
}
return master.NewEtcdHelper(client, storageVersion)
return master.NewEtcdHelper(client, storageVersion, pathPrefix)
}
// Run runs the specified APIServer. This should never exit.
......@@ -232,7 +235,7 @@ func (s *APIServer) Run(_ []string) error {
glog.Fatalf("Invalid server address: %v", err)
}
helper, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, s.StorageVersion)
helper, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, s.StorageVersion, s.EtcdPathPrefix)
if err != nil {
glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err)
}
......
......@@ -81,7 +81,7 @@ func (h *delegateHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServiceNamespace string) {
handler := delegateHandler{}
helper, err := master.NewEtcdHelper(etcdClient, "")
helper, err := master.NewEtcdHelper(etcdClient, "", master.DefaultEtcdPathPrefix)
if err != nil {
glog.Fatalf("Unable to get etcd helper: %v", err)
}
......
......@@ -53,6 +53,9 @@ KUBE_RACE=${KUBE_RACE:-} # use KUBE_RACE="-race" to enable race testing
KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
# Comma separated list of API Versions that should be tested.
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta1,v1beta3"}
# Prefixes for etcd paths (standard and customized)
ETCD_STANDARD_PREFIX="registry"
ETCD_CUSTOM_PREFIX="kubernetes.io/registry"
kube::test::usage() {
kube::log::usage_from_stdin <<EOF
......@@ -203,10 +206,13 @@ reportCoverageToCoveralls() {
# Convert the CSV to an array of API versions to test
IFS=',' read -a apiVersions <<< "${KUBE_TEST_API_VERSIONS}"
ETCD_PREFIX=${ETCD_STANDARD_PREFIX}
for apiVersion in "${apiVersions[@]}"; do
echo "Running tests for APIVersion: $apiVersion"
KUBE_API_VERSION="${apiVersion}" runTests "$@"
KUBE_API_VERSION="${apiVersion}" ETCD_PREFIX=${ETCD_STANDARD_PREFIX} runTests "$@"
done
echo "Using custom etcd path prefix: ${ETCD_CUSTOM_PREFIX}"
KUBE_API_VERSION="${apiVersions[-1]}" ETCD_PREFIX=${ETCD_CUSTOM_PREFIX} runTests "$@"
# We might run the tests for multiple versions, but we want to report only
# one of them to coveralls. Here we report coverage from the last run.
......
......@@ -271,7 +271,6 @@ func (t *Tester) TestDeleteNoGraceful(createFn func() runtime.Object, wasGracefu
if err != nil {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing)
}
ctx := api.WithNamespace(api.NewContext(), objectMeta.Namespace)
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10))
if err != nil {
......
......@@ -71,6 +71,10 @@ import (
"github.com/golang/glog"
)
const (
DefaultEtcdPathPrefix = "/registry"
)
// Config is a structure used to configure a Master.
type Config struct {
EtcdHelper tools.EtcdHelper
......@@ -178,7 +182,7 @@ type Master struct {
// NewEtcdHelper returns an EtcdHelper for the provided arguments or an error if the version
// is incorrect.
func NewEtcdHelper(client tools.EtcdGetSet, version string) (helper tools.EtcdHelper, err error) {
func NewEtcdHelper(client tools.EtcdGetSet, version string, prefix string) (helper tools.EtcdHelper, err error) {
if version == "" {
version = latest.Version
}
......@@ -186,7 +190,7 @@ func NewEtcdHelper(client tools.EtcdGetSet, version string) (helper tools.EtcdHe
if err != nil {
return helper, err
}
return tools.NewEtcdHelper(client, versionInterfaces.Codec), nil
return tools.NewEtcdHelper(client, versionInterfaces.Codec, prefix), nil
}
// setDefaults fills in any fields not set that are required to have valid data.
......@@ -363,7 +367,7 @@ func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter)
func (m *Master) init(c *Config) {
// TODO: make initialization of the helper part of the Master, and allow some storage
// objects to have a newer storage version than the user's default.
newerHelper, err := NewEtcdHelper(c.EtcdHelper.Client, "v1beta3")
newerHelper, err := NewEtcdHelper(c.EtcdHelper.Client, "v1beta3", DefaultEtcdPathPrefix)
if err != nil {
glog.Fatalf("Unable to setup storage for v1beta3: %v", err)
}
......
......@@ -23,6 +23,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
)
func TestGetServersToValidate(t *testing.T) {
......@@ -30,7 +31,7 @@ func TestGetServersToValidate(t *testing.T) {
config := Config{}
fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
config.EtcdHelper = tools.EtcdHelper{fakeClient, latest.Codec, nil}
config.EtcdHelper = tools.EtcdHelper{fakeClient, latest.Codec, nil, etcdtest.PathPrefix()}
master.nodeRegistry = registrytest.NewMinionRegistry([]string{"node1", "node2"}, api.NodeResources{})
......
......@@ -34,7 +34,7 @@ type REST struct {
// controllerPrefix is the location for controllers in etcd, only exposed
// for testing
var controllerPrefix = "/registry/controllers"
var controllerPrefix = "/controllers"
// NewREST returns a RESTStorage object that will work against replication controllers.
func NewREST(h tools.EtcdHelper) *REST {
......
......@@ -31,6 +31,7 @@ import (
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/coreos/go-etcd/etcd"
)
......@@ -39,11 +40,16 @@ const (
FAIL
)
// newStorage creates a REST storage backed by etcd helpers
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
h := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
return fakeEtcdClient, helper
}
// newStorage creates a REST storage backed by etcd helpers
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
fakeEtcdClient, h := newHelper(t)
storage := NewREST(h)
return storage, fakeEtcdClient
}
......@@ -107,6 +113,7 @@ func TestEtcdCreateController(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
resp, err := fakeClient.Get(key, false, false)
if err != nil {
t.Fatalf("Unexpected error %v", err)
......@@ -126,6 +133,7 @@ func TestEtcdCreateControllerAlreadyExisting(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0)
_, err := storage.Create(ctx, &validController)
......@@ -199,6 +207,7 @@ func TestEtcdGetController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0)
ctrl, err := storage.Get(ctx, validController.Name)
if err != nil {
......@@ -282,6 +291,9 @@ func TestEtcdGetControllerDifferentNamespace(t *testing.T) {
key1, _ := makeControllerKey(ctx1, validController.Name)
key2, _ := makeControllerKey(ctx2, validController.Name)
key1 = etcdtest.AddPrefix(key1)
key2 = etcdtest.AddPrefix(key2)
fakeClient.Set(key1, runtime.EncodeOrDie(latest.Codec, &validController), 0)
otherNsController := validController
otherNsController.Namespace = otherNs
......@@ -317,6 +329,8 @@ func TestEtcdGetControllerNotFound(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
......@@ -336,6 +350,7 @@ func TestEtcdUpdateController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
// set a key, then retrieve the current resource version and try updating it
resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0)
......@@ -360,6 +375,8 @@ func TestEtcdDeleteController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0)
obj, err := storage.Delete(ctx, validController.Name, nil)
if err != nil {
......@@ -382,6 +399,7 @@ func TestEtcdListControllers(t *testing.T) {
storage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
key := makeControllerListKey(ctx)
key = etcdtest.AddPrefix(key)
controller := validController
controller.Name = "bar"
fakeClient.Data[key] = tools.EtcdResponseWithError{
......@@ -413,6 +431,8 @@ func TestEtcdListControllersNotFound(t *testing.T) {
storage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
key := makeControllerListKey(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
......@@ -431,6 +451,7 @@ func TestEtcdListControllersLabelsMatch(t *testing.T) {
storage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
key := makeControllerListKey(ctx)
key = etcdtest.AddPrefix(key)
controller := validController
controller.Labels = map[string]string{"k": "v"}
......@@ -678,13 +699,16 @@ func TestCreate(t *testing.T) {
}
func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
rc := validController
rc.ResourceVersion = "1"
fakeClient.Data["/registry/controllers/default/foo"] = tools.EtcdResponseWithError{
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, &rc),
......@@ -697,7 +721,7 @@ func TestDelete(t *testing.T) {
gracefulSetFn := func() bool {
// If the controller is still around after trying to delete either the delete
// failed, or we're deleting it gracefully.
if fakeClient.Data["/registry/controllers/default/foo"].R.Node != nil {
if fakeClient.Data[key].R.Node != nil {
return true
}
return false
......
......@@ -34,7 +34,7 @@ type REST struct {
// NewStorage returns a RESTStorage object that will work against endpoints.
func NewStorage(h tools.EtcdHelper) *REST {
prefix := "/registry/services/endpoints"
prefix := "/services/endpoints"
return &REST{
&etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Endpoints{} },
......
......@@ -26,6 +26,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -34,7 +35,7 @@ import (
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
return fakeEtcdClient, helper
}
......@@ -89,6 +90,7 @@ func TestDelete(t *testing.T) {
endpoints := validChangedEndpoints()
key, _ := storage.KeyFunc(ctx, endpoints.Name)
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......@@ -113,6 +115,7 @@ func TestEtcdListEndpoints(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -154,6 +157,7 @@ func TestEtcdGetEndpoints(t *testing.T) {
endpoints := validNewEndpoints()
name := endpoints.Name
key, _ := storage.KeyFunc(ctx, name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, endpoints), 0)
response, err := fakeClient.Get(key, false, false)
......@@ -183,6 +187,7 @@ func TestListEmptyEndpointsList(t *testing.T) {
storage, fakeClient := newStorage(t)
fakeClient.ChangeIndex = 1
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: fakeClient.NewError(tools.EtcdErrorCodeNotFound),
......@@ -206,6 +211,7 @@ func TestListEndpointsList(t *testing.T) {
storage, fakeClient := newStorage(t)
fakeClient.ChangeIndex = 1
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -266,6 +272,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
endpoints := validChangedEndpoints()
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewEndpoints()), 0)
_, _, err := storage.Update(ctx, endpoints)
......@@ -295,6 +302,7 @@ func TestDeleteEndpoints(t *testing.T) {
endpoints := validNewEndpoints()
name := endpoints.Name
key, _ := storage.KeyFunc(ctx, name)
key = etcdtest.AddPrefix(key)
fakeClient.ChangeIndex = 1
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......
......@@ -35,9 +35,9 @@ import (
const (
// ControllerPath is the path to controller resources in etcd
ControllerPath string = "/registry/controllers"
ControllerPath string = "/controllers"
// ServicePath is the path to service resources in etcd
ServicePath string = "/registry/services/specs"
ServicePath string = "/services/specs"
)
// TODO: Need to add a reconciler loop that makes sure that things in pods are reflected into
......
......@@ -32,16 +32,17 @@ type registry struct {
// NewEtcdRegistry returns a registry which will store Events in the given
// EtcdHelper. ttl is the time that Events will be retained by the system.
func NewEtcdRegistry(h tools.EtcdHelper, ttl uint64) generic.Registry {
prefix := "/events"
return registry{
Etcd: &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Event{} },
NewListFunc: func() runtime.Object { return &api.EventList{} },
EndpointName: "events",
KeyRootFunc: func(ctx api.Context) string {
return etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/events")
return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
},
KeyFunc: func(ctx api.Context, id string) (string, error) {
return etcdgeneric.NamespaceKeyFunc(ctx, "/registry/events", id)
return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
},
TTLFunc: func(runtime.Object, bool) (uint64, error) {
return ttl, nil
......
......@@ -27,6 +27,7 @@ import (
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -37,7 +38,8 @@ var testTTL uint64 = 60
func NewTestEventEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, generic.Registry) {
f := tools.NewFakeEtcdClient(t)
f.TestIndex = true
h := tools.NewEtcdHelper(f, testapi.Codec())
h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix())
return f, NewEtcdRegistry(h, testTTL)
}
......@@ -70,7 +72,8 @@ func TestEventCreate(t *testing.T) {
ctx := api.NewDefaultContext()
key := "foo"
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/registry/events", key)
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/events", key)
path = etcdtest.AddPrefix(path)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
......@@ -166,7 +169,8 @@ func TestEventUpdate(t *testing.T) {
ctx := api.NewDefaultContext()
key := "foo"
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/registry/events", key)
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/events", key)
path = etcdtest.AddPrefix(path)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
......
......@@ -27,6 +27,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/fielderrors"
......@@ -66,17 +67,20 @@ func hasCreated(t *testing.T, pod *api.Pod) func(runtime.Object) bool {
func NewTestGenericEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, *Etcd) {
f := tools.NewFakeEtcdClient(t)
f.TestIndex = true
h := tools.NewEtcdHelper(f, testapi.Codec())
h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix())
strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false}
podPrefix := "/pods"
return f, &Etcd{
NewFunc: func() runtime.Object { return &api.Pod{} },
NewListFunc: func() runtime.Object { return &api.PodList{} },
EndpointName: "pods",
CreateStrategy: strategy,
UpdateStrategy: strategy,
KeyRootFunc: func(ctx api.Context) string { return "/registry/pods" },
KeyRootFunc: func(ctx api.Context) string {
return podPrefix
},
KeyFunc: func(ctx api.Context, id string) (string, error) {
return path.Join("/registry/pods", id), nil
return path.Join(podPrefix, id), nil
},
ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil },
Helper: h,
......@@ -205,16 +209,18 @@ func TestEtcdList(t *testing.T) {
t.Errorf("Couldn't create key for %v", name)
continue
}
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = item.in
} else {
fakeClient.Data[registry.KeyRootFunc(api.NewContext())] = item.in
key, _ := registry.KeyFunc(api.NewContext(), name)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = item.in
}
list, err := registry.ListPredicate(api.NewContext(), item.m)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
continue
}
if e, a := item.out, list; !api.Semantic.DeepDerivative(e, a) {
t.Errorf("%v: Expected %#v, got %#v", name, e, a)
}
......@@ -247,8 +253,6 @@ func TestEtcdCreate(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
path := "/registry/pods/foo"
table := map[string]struct {
existing tools.EtcdResponseWithError
expect tools.EtcdResponseWithError
......@@ -272,6 +276,7 @@ func TestEtcdCreate(t *testing.T) {
for name, item := range table {
fakeClient, registry := NewTestGenericEtcdRegistry(t)
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
obj, err := registry.Create(api.NewDefaultContext(), item.toCreate)
if !item.errOK(err) {
......@@ -326,7 +331,6 @@ func TestEtcdCreateWithName(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
path := "/registry/pods/foo"
key := "foo"
table := map[string]struct {
......@@ -352,6 +356,7 @@ func TestEtcdCreateWithName(t *testing.T) {
for name, item := range table {
fakeClient, registry := NewTestGenericEtcdRegistry(t)
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
err := registry.CreateWithName(api.NewDefaultContext(), key, item.toCreate)
if !item.errOK(err) {
......@@ -424,8 +429,6 @@ func TestEtcdUpdate(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
path := "/registry/pods/foo"
table := map[string]struct {
existing tools.EtcdResponseWithError
expect tools.EtcdResponseWithError
......@@ -464,6 +467,7 @@ func TestEtcdUpdate(t *testing.T) {
for name, item := range table {
fakeClient, registry := NewTestGenericEtcdRegistry(t)
registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = item.allowCreate
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
obj, _, err := registry.Update(api.NewDefaultContext(), item.toUpdate)
if !item.errOK(err) {
......@@ -529,7 +533,6 @@ func TestEtcdUpdateWithName(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
path := "/registry/pods/foo"
key := "foo"
table := map[string]struct {
......@@ -555,6 +558,7 @@ func TestEtcdUpdateWithName(t *testing.T) {
for name, item := range table {
fakeClient, registry := NewTestGenericEtcdRegistry(t)
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
err := registry.UpdateWithName(api.NewContext(), key, item.toUpdate)
if !item.errOK(err) {
......@@ -589,7 +593,6 @@ func TestEtcdGet(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
path := "/registry/pods/foo"
key := "foo"
table := map[string]struct {
......@@ -611,6 +614,7 @@ func TestEtcdGet(t *testing.T) {
for name, item := range table {
fakeClient, registry := NewTestGenericEtcdRegistry(t)
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
got, err := registry.Get(api.NewContext(), key)
if !item.errOK(err) {
......@@ -645,7 +649,6 @@ func TestEtcdDelete(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
path := "/registry/pods/foo"
key := "foo"
table := map[string]struct {
......@@ -667,6 +670,7 @@ func TestEtcdDelete(t *testing.T) {
for name, item := range table {
fakeClient, registry := NewTestGenericEtcdRegistry(t)
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
obj, err := registry.Delete(api.NewContext(), key, nil)
if !item.errOK(err) {
......
......@@ -31,16 +31,17 @@ type registry struct {
// NewEtcdRegistry returns a registry which will store LimitRange in the given helper
func NewEtcdRegistry(h tools.EtcdHelper) generic.Registry {
prefix := "/limitranges"
return registry{
Etcd: &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.LimitRange{} },
NewListFunc: func() runtime.Object { return &api.LimitRangeList{} },
EndpointName: "limitranges",
KeyRootFunc: func(ctx api.Context) string {
return etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/limitranges")
return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
},
KeyFunc: func(ctx api.Context, id string) (string, error) {
return etcdgeneric.NamespaceKeyFunc(ctx, "/registry/limitranges", id)
return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
},
Helper: h,
},
......
......@@ -28,6 +28,7 @@ import (
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -36,7 +37,7 @@ import (
func NewTestLimitRangeEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, generic.Registry) {
f := tools.NewFakeEtcdClient(t)
f.TestIndex = true
h := tools.NewEtcdHelper(f, testapi.Codec())
h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix())
return f, NewEtcdRegistry(h)
}
......@@ -81,7 +82,9 @@ func TestLimitRangeCreate(t *testing.T) {
ctx := api.NewDefaultContext()
key := "foo"
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/registry/limitranges", key)
prefix := etcdtest.AddPrefix("limitranges")
path, err := etcdgeneric.NamespaceKeyFunc(ctx, prefix, key)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
......
......@@ -50,7 +50,7 @@ func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object
// NewStorage returns a RESTStorage object that will work against nodes.
func NewStorage(h tools.EtcdHelper, connection client.ConnectionInfoGetter) (*REST, *StatusREST) {
prefix := "/registry/minions"
prefix := "/minions"
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Node{} },
NewListFunc: func() runtime.Object { return &api.NodeList{} },
......
......@@ -30,6 +30,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/coreos/go-etcd/etcd"
)
......@@ -49,7 +50,7 @@ func (fakeConnectionInfoGetter) GetConnectionInfo(host string) (string, uint, ht
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
return fakeEtcdClient, helper
}
......@@ -107,6 +108,7 @@ func TestDelete(t *testing.T) {
node := validChangedNode()
key, _ := storage.KeyFunc(ctx, node.Name)
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......@@ -131,6 +133,7 @@ func TestEtcdListNodes(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t)
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -165,6 +168,7 @@ func TestEtcdListNodesMatch(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t)
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -209,6 +213,7 @@ func TestEtcdGetNode(t *testing.T) {
storage, fakeClient := newStorage(t)
node := validNewNode()
key, _ := storage.KeyFunc(ctx, node.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, node), 0)
nodeObj, err := storage.Get(ctx, node.Name)
......@@ -229,6 +234,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
node := validChangedNode()
key, _ := storage.KeyFunc(ctx, node.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewNode()), 0)
_, _, err := storage.Update(ctx, node)
......@@ -255,7 +261,8 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
func TestEtcdGetNodeNotFound(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t)
fakeClient.Data["/registry/minions/foo"] = tools.EtcdResponseWithError{
key := etcdtest.AddPrefix("minions/foo")
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
},
......@@ -273,6 +280,7 @@ func TestEtcdDeleteNode(t *testing.T) {
storage, fakeClient := newStorage(t)
node := validNewNode()
key, _ := storage.KeyFunc(ctx, node.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, node), 0)
_, err := storage.Delete(ctx, node.Name, nil)
if err != nil {
......
......@@ -18,6 +18,7 @@ package etcd
import (
"fmt"
"path"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
......@@ -48,14 +49,15 @@ type FinalizeREST struct {
// NewStorage returns a RESTStorage object that will work against namespaces
func NewStorage(h tools.EtcdHelper) (*REST, *StatusREST, *FinalizeREST) {
prefix := "/namespaces"
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Namespace{} },
NewListFunc: func() runtime.Object { return &api.NamespaceList{} },
KeyRootFunc: func(ctx api.Context) string {
return "/registry/namespaces"
return prefix
},
KeyFunc: func(ctx api.Context, name string) (string, error) {
return "/registry/namespaces/" + name, nil
return path.Join(prefix, name), nil
},
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*api.Namespace).Name, nil
......
......@@ -27,6 +27,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/namespace"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -35,7 +36,7 @@ import (
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
return fakeEtcdClient, helper
}
......@@ -102,7 +103,12 @@ func TestCreateSetsFields(t *testing.T) {
}
actual := &api.Namespace{}
if err := helper.ExtractObj("/registry/namespaces/foo", actual, false); err != nil {
ctx := api.NewDefaultContext()
key, err := storage.Etcd.KeyFunc(ctx, "foo")
if err != nil {
t.Fatalf("unexpected key error: %v", err)
}
if err := helper.ExtractObj(key, actual, false); err != nil {
t.Fatalf("unexpected extraction error: %v", err)
}
if actual.Name != namespace.Name {
......@@ -119,7 +125,8 @@ func TestCreateSetsFields(t *testing.T) {
func TestListEmptyNamespaceList(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.ChangeIndex = 1
fakeEtcdClient.Data["/registry/namespaces"] = tools.EtcdResponseWithError{
key := etcdtest.AddPrefix("/namespaces")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: fakeEtcdClient.NewError(tools.EtcdErrorCodeNotFound),
}
......@@ -139,7 +146,8 @@ func TestListEmptyNamespaceList(t *testing.T) {
func TestListNamespaceList(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.Data["/registry/namespaces"] = tools.EtcdResponseWithError{
key := etcdtest.AddPrefix("/namespaces")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
......@@ -177,7 +185,8 @@ func TestListNamespaceList(t *testing.T) {
func TestListNamespaceListSelection(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.Data["/registry/namespaces"] = tools.EtcdResponseWithError{
key := etcdtest.AddPrefix("/namespaces")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
......@@ -275,15 +284,20 @@ func TestNamespaceDecode(t *testing.T) {
func TestGet(t *testing.T) {
expect := validNewNamespace()
expect.Status.Phase = api.NamespaceActive
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.Data["/registry/namespaces/foo"] = tools.EtcdResponseWithError{
storage, fakeEtcdClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key, err := storage.Etcd.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
if err != nil {
t.Fatalf("unexpected key error: %v", err)
}
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, expect),
},
},
}
storage, _, _ := NewStorage(helper)
obj, err := storage.Get(api.NewContext(), "foo")
namespace := obj.(*api.Namespace)
if err != nil {
......@@ -299,7 +313,11 @@ func TestGet(t *testing.T) {
func TestDeleteNamespace(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.ChangeIndex = 1
fakeEtcdClient.Data["/registry/namespaces/foo"] = tools.EtcdResponseWithError{
storage, _, _ := NewStorage(helper)
ctx := api.NewDefaultContext()
key, err := storage.Etcd.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, &api.Namespace{
......@@ -313,8 +331,7 @@ func TestDeleteNamespace(t *testing.T) {
},
},
}
storage, _, _ := NewStorage(helper)
_, err := storage.Delete(api.NewDefaultContext(), "foo", nil)
_, err = storage.Delete(api.NewDefaultContext(), "foo", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
......@@ -325,7 +342,8 @@ func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
now := util.Now()
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.ChangeIndex = 1
fakeEtcdClient.Data["/registry/namespaces/foo"] = tools.EtcdResponseWithError{
key := etcdtest.AddPrefix("/namespaces/foo")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, &api.Namespace{
......@@ -354,7 +372,8 @@ func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
now := util.Now()
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.ChangeIndex = 1
fakeEtcdClient.Data["/registry/namespaces/foo"] = tools.EtcdResponseWithError{
key := etcdtest.AddPrefix("/namespaces/foo")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, &api.Namespace{
......
......@@ -17,6 +17,8 @@ limitations under the License.
package etcd
import (
"path"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
......@@ -34,7 +36,7 @@ type REST struct {
// NewREST returns a RESTStorage object that will work against PersistentVolume objects.
func NewStorage(h tools.EtcdHelper) (*REST, *StatusREST) {
prefix := "/registry/persistentvolumes"
prefix := "/persistentvolumes"
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.PersistentVolume{} },
NewListFunc: func() runtime.Object { return &api.PersistentVolumeList{} },
......@@ -42,7 +44,7 @@ func NewStorage(h tools.EtcdHelper) (*REST, *StatusREST) {
return prefix
},
KeyFunc: func(ctx api.Context, name string) (string, error) {
return prefix + "/" + name, nil
return path.Join(prefix, name), nil
},
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*api.PersistentVolume).Name, nil
......
......@@ -28,6 +28,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -40,7 +41,7 @@ type testRegistry struct {
func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
storage, statusStorage := NewStorage(helper)
return storage, statusStorage, fakeEtcdClient, helper
}
......@@ -90,6 +91,7 @@ func TestDelete(t *testing.T) {
pv := validChangedPersistentVolume()
key, _ := storage.KeyFunc(ctx, pv.Name)
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......@@ -114,6 +116,7 @@ func TestEtcdListPersistentVolumes(t *testing.T) {
ctx := api.NewDefaultContext()
storage, _, fakeClient, _ := newStorage(t)
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -147,6 +150,7 @@ func TestEtcdGetPersistentVolumes(t *testing.T) {
persistentVolume := validNewPersistentVolume("foo")
name := persistentVolume.Name
key, _ := storage.KeyFunc(ctx, name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, persistentVolume), 0)
response, err := fakeClient.Get(key, false, false)
......@@ -176,6 +180,7 @@ func TestListEmptyPersistentVolumesList(t *testing.T) {
storage, _, fakeClient, _ := newStorage(t)
fakeClient.ChangeIndex = 1
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: fakeClient.NewError(tools.EtcdErrorCodeNotFound),
......@@ -199,6 +204,7 @@ func TestListPersistentVolumesList(t *testing.T) {
storage, _, fakeClient, _ := newStorage(t)
fakeClient.ChangeIndex = 1
key := storage.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -259,6 +265,7 @@ func TestEtcdUpdatePersistentVolumes(t *testing.T) {
persistentVolume := validChangedPersistentVolume()
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewPersistentVolume("foo")), 0)
_, _, err := storage.Update(ctx, persistentVolume)
......@@ -288,6 +295,7 @@ func TestDeletePersistentVolumes(t *testing.T) {
persistentVolume := validNewPersistentVolume("foo")
name := persistentVolume.Name
key, _ := storage.KeyFunc(ctx, name)
key = etcdtest.AddPrefix(key)
fakeClient.ChangeIndex = 1
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......@@ -310,6 +318,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
pvStart := validNewPersistentVolume("foo")
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, pvStart), 1)
......@@ -333,6 +342,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
var pvOut api.PersistentVolume
key, _ = storage.KeyFunc(ctx, "foo")
if err := helper.ExtractObj(key, &pvOut, false); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......
......@@ -34,7 +34,7 @@ type REST struct {
// NewREST returns a RESTStorage object that will work against PersistentVolumeClaim objects.
func NewStorage(h tools.EtcdHelper) (*REST, *StatusREST) {
prefix := "/registry/persistentvolumeclaims"
prefix := "/persistentvolumeclaims"
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.PersistentVolumeClaim{} },
NewListFunc: func() runtime.Object { return &api.PersistentVolumeClaimList{} },
......
......@@ -28,6 +28,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -40,7 +41,7 @@ type testRegistry struct {
func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
storage, statusStorage := NewStorage(helper)
return storage, statusStorage, fakeEtcdClient, helper
}
......@@ -92,6 +93,7 @@ func TestDelete(t *testing.T) {
pv := validChangedPersistentVolumeClaim()
key, _ := storage.KeyFunc(ctx, pv.Name)
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......@@ -116,6 +118,7 @@ func TestEtcdListPersistentVolumeClaims(t *testing.T) {
ctx := api.NewDefaultContext()
registry, _, fakeClient, _ := newStorage(t)
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -149,6 +152,7 @@ func TestEtcdGetPersistentVolumeClaims(t *testing.T) {
persistentVolume := validNewPersistentVolumeClaim("foo", api.NamespaceDefault)
name := persistentVolume.Name
key, _ := registry.KeyFunc(ctx, name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, persistentVolume), 0)
response, err := fakeClient.Get(key, false, false)
......@@ -178,6 +182,7 @@ func TestListEmptyPersistentVolumeClaimsList(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
fakeClient.ChangeIndex = 1
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: fakeClient.NewError(tools.EtcdErrorCodeNotFound),
......@@ -201,6 +206,7 @@ func TestListPersistentVolumeClaimsList(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
fakeClient.ChangeIndex = 1
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -261,6 +267,7 @@ func TestEtcdUpdatePersistentVolumeClaims(t *testing.T) {
persistentVolume := validChangedPersistentVolumeClaim()
key, _ := registry.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewPersistentVolumeClaim("foo", api.NamespaceDefault)), 0)
_, _, err := registry.Update(ctx, persistentVolume)
......@@ -290,6 +297,7 @@ func TestDeletePersistentVolumeClaims(t *testing.T) {
pvClaim := validNewPersistentVolumeClaim("foo", api.NamespaceDefault)
name := pvClaim.Name
key, _ := registry.KeyFunc(ctx, name)
key = etcdtest.AddPrefix(key)
fakeClient.ChangeIndex = 1
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......@@ -312,6 +320,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
pvcStart := validNewPersistentVolumeClaim("foo", api.NamespaceDefault)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, pvcStart), 1)
......@@ -336,6 +345,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
var pvcOut api.PersistentVolumeClaim
key, _ = storage.KeyFunc(ctx, "foo")
if err := helper.ExtractObj(key, &pvcOut, false); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......
......@@ -56,7 +56,7 @@ type REST struct {
// NewStorage returns a RESTStorage object that will work against pods.
func NewStorage(h tools.EtcdHelper, k client.ConnectionInfoGetter) PodStorage {
prefix := "/registry/pods"
prefix := "/pods"
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Pod{} },
NewListFunc: func() runtime.Object { return &api.PodList{} },
......
......@@ -34,7 +34,7 @@ type REST struct {
// NewREST returns a RESTStorage object that will work against pod templates.
func NewREST(h tools.EtcdHelper) *REST {
prefix := "/registry/podtemplates"
prefix := "/podtemplates"
store := etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.PodTemplate{} },
NewListFunc: func() runtime.Object { return &api.PodTemplateList{} },
......
......@@ -23,12 +23,13 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
)
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, v1beta3.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, v1beta3.Codec, etcdtest.PathPrefix())
return fakeEtcdClient, helper
}
......@@ -79,8 +80,9 @@ func TestUpdate(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
storage := NewREST(helper)
test := resttest.New(t, storage, fakeEtcdClient.SetError)
key := etcdtest.AddPrefix("podtemplates/default/foo")
fakeEtcdClient.ExpectNotFoundGet("/registry/podtemplates/default/foo")
fakeEtcdClient.ExpectNotFoundGet(key)
fakeEtcdClient.ChangeIndex = 2
pod := validNewPodTemplate("foo")
existing := validNewPodTemplate("exists")
......
......@@ -34,7 +34,7 @@ type REST struct {
// NewStorage returns a RESTStorage object that will work against ResourceQuota objects.
func NewStorage(h tools.EtcdHelper) (*REST, *StatusREST) {
prefix := "/registry/resourcequotas"
prefix := "/resourcequotas"
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.ResourceQuota{} },
NewListFunc: func() runtime.Object { return &api.ResourceQuotaList{} },
......
......@@ -32,6 +32,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequota"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -40,7 +41,7 @@ import (
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec)
helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
return fakeEtcdClient, helper
}
......@@ -123,6 +124,7 @@ func TestCreateRegistryError(t *testing.T) {
func TestCreateSetsFields(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
storage, _ := NewStorage(helper)
ctx := api.NewDefaultContext()
resourcequota := validNewResourceQuota()
_, err := storage.Create(api.NewDefaultContext(), resourcequota)
if err != fakeEtcdClient.Err {
......@@ -130,7 +132,8 @@ func TestCreateSetsFields(t *testing.T) {
}
actual := &api.ResourceQuota{}
if err := helper.ExtractObj("/registry/resourcequotas/default/foo", actual, false); err != nil {
key, _ := storage.Etcd.KeyFunc(ctx, "foo")
if err := helper.ExtractObj(key, actual, false); err != nil {
t.Fatalf("unexpected extraction error: %v", err)
}
if actual.Name != resourcequota.Name {
......@@ -157,12 +160,16 @@ func TestListError(t *testing.T) {
func TestListEmptyResourceQuotaList(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.ChangeIndex = 1
fakeEtcdClient.Data["/registry/resourcequotas"] = tools.EtcdResponseWithError{
storage, _ := NewStorage(helper)
ctx := api.NewContext()
key := storage.Etcd.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: fakeEtcdClient.NewError(tools.EtcdErrorCodeNotFound),
}
storage, _ := NewStorage(helper)
resourcequotas, err := storage.List(api.NewContext(), labels.Everything(), fields.Everything())
if err != nil {
t.Fatalf("unexpected error: %v", err)
......@@ -178,7 +185,11 @@ func TestListEmptyResourceQuotaList(t *testing.T) {
func TestListResourceQuotaList(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.Data["/registry/resourcequotas/default"] = tools.EtcdResponseWithError{
storage, _ := NewStorage(helper)
ctx := api.NewDefaultContext()
key := storage.Etcd.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
......@@ -196,7 +207,6 @@ func TestListResourceQuotaList(t *testing.T) {
},
},
}
storage, _ := NewStorage(helper)
resourcequotasObj, err := storage.List(api.NewDefaultContext(), labels.Everything(), fields.Everything())
resourcequotas := resourcequotasObj.(*api.ResourceQuotaList)
if err != nil {
......@@ -216,7 +226,11 @@ func TestListResourceQuotaList(t *testing.T) {
func TestListResourceQuotaListSelection(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.Data["/registry/resourcequotas/default"] = tools.EtcdResponseWithError{
storage, _ := NewStorage(helper)
ctx := api.NewDefaultContext()
key := storage.Etcd.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
......@@ -236,8 +250,6 @@ func TestListResourceQuotaListSelection(t *testing.T) {
},
},
}
storage, _ := NewStorage(helper)
ctx := api.NewDefaultContext()
table := []struct {
label, field string
......@@ -302,14 +314,16 @@ func TestResourceQuotaDecode(t *testing.T) {
func TestGet(t *testing.T) {
expect := validNewResourceQuota()
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.Data["/registry/resourcequotas/test/foo"] = tools.EtcdResponseWithError{
storage, _ := NewStorage(helper)
key := "/resourcequotas/test/foo"
key = etcdtest.AddPrefix(key)
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, expect),
},
},
}
storage, _ := NewStorage(helper)
obj, err := storage.Get(api.WithNamespace(api.NewContext(), "test"), "foo")
resourcequota := obj.(*api.ResourceQuota)
if err != nil {
......@@ -324,7 +338,11 @@ func TestGet(t *testing.T) {
func TestDeleteResourceQuota(t *testing.T) {
fakeEtcdClient, helper := newHelper(t)
fakeEtcdClient.ChangeIndex = 1
fakeEtcdClient.Data["/registry/resourcequotas/default/foo"] = tools.EtcdResponseWithError{
storage, _ := NewStorage(helper)
ctx := api.NewDefaultContext()
key, _ := storage.Etcd.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, &api.ResourceQuota{
......@@ -339,7 +357,6 @@ func TestDeleteResourceQuota(t *testing.T) {
},
},
}
storage, _ := NewStorage(helper)
_, err := storage.Delete(api.NewDefaultContext(), "foo", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
......@@ -356,6 +373,9 @@ func TestEtcdGetDifferentNamespace(t *testing.T) {
key1, _ := registry.KeyFunc(ctx1, "foo")
key2, _ := registry.KeyFunc(ctx2, "foo")
key1 = etcdtest.AddPrefix(key1)
key2 = etcdtest.AddPrefix(key2)
fakeClient.Set(key1, runtime.EncodeOrDie(latest.Codec, &api.ResourceQuota{ObjectMeta: api.ObjectMeta{Namespace: "default", Name: "foo"}}), 0)
fakeClient.Set(key2, runtime.EncodeOrDie(latest.Codec, &api.ResourceQuota{ObjectMeta: api.ObjectMeta{Namespace: "other", Name: "foo"}}), 0)
......@@ -389,6 +409,7 @@ func TestEtcdGet(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key, _ := registry.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.ResourceQuota{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0)
obj, err := registry.Get(ctx, "foo")
if err != nil {
......@@ -404,6 +425,7 @@ func TestEtcdGetNotFound(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key, _ := registry.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
......@@ -432,6 +454,7 @@ func TestEtcdCreateAlreadyExisting(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key, _ := registry.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -452,6 +475,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
fakeClient.TestIndex = true
key, _ := registry.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
resourcequotaStart := validNewResourceQuota()
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, resourcequotaStart), 1)
......@@ -491,6 +515,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
var resourcequotaOut api.ResourceQuota
key, _ = registry.KeyFunc(ctx, "foo")
if err := helper.ExtractObj(key, &resourcequotaOut, false); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -503,6 +528,7 @@ func TestEtcdEmptyList(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......@@ -526,6 +552,7 @@ func TestEtcdListNotFound(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
......@@ -544,6 +571,7 @@ func TestEtcdList(t *testing.T) {
registry, _, fakeClient, _ := newStorage(t)
ctx := api.NewDefaultContext()
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
......
......@@ -31,16 +31,17 @@ type registry struct {
// NewEtcdRegistry returns a registry which will store Secret in the given helper
func NewEtcdRegistry(h tools.EtcdHelper) generic.Registry {
prefix := "/secrets"
return registry{
Etcd: &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Secret{} },
NewListFunc: func() runtime.Object { return &api.SecretList{} },
EndpointName: "secrets",
KeyRootFunc: func(ctx api.Context) string {
return etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/secrets")
return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
},
KeyFunc: func(ctx api.Context, id string) (string, error) {
return etcdgeneric.NamespaceKeyFunc(ctx, "/registry/secrets", id)
return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
},
Helper: h,
},
......
......@@ -27,6 +27,7 @@ import (
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
......@@ -35,7 +36,7 @@ import (
func NewTestSecretEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, generic.Registry) {
f := tools.NewFakeEtcdClient(t)
f.TestIndex = true
h := tools.NewEtcdHelper(f, testapi.Codec())
h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix())
return f, NewEtcdRegistry(h)
}
......@@ -65,10 +66,11 @@ func TestSecretCreate(t *testing.T) {
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
ctx := api.NewDefaultContext()
key := "foo"
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/registry/secrets", key)
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/secrets", key)
path = etcdtest.AddPrefix(path)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
......
......@@ -23,7 +23,9 @@ import (
"io/ioutil"
"net/http"
"os/exec"
"path"
"reflect"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
......@@ -38,15 +40,18 @@ type EtcdHelper struct {
Codec runtime.Codec
// optional, no atomic operations can be performed without this interface
Versioner EtcdVersioner
// prefix for all etcd keys
PathPrefix string
}
// NewEtcdHelper creates a helper that works against objects that use the internal
// Kubernetes API objects.
func NewEtcdHelper(client EtcdGetSet, codec runtime.Codec) EtcdHelper {
func NewEtcdHelper(client EtcdGetSet, codec runtime.Codec, prefix string) EtcdHelper {
return EtcdHelper{
Client: client,
Codec: codec,
Versioner: APIObjectVersioner{},
Client: client,
Codec: codec,
Versioner: APIObjectVersioner{},
PathPrefix: prefix,
}
}
......@@ -136,6 +141,7 @@ func (h *EtcdHelper) ExtractToList(key string, listObj runtime.Object) error {
if err != nil {
return err
}
key = h.PrefixEtcdKey(key)
nodes, index, err := h.listEtcdNode(key)
if err != nil {
return err
......@@ -158,7 +164,7 @@ func (h *EtcdHelper) ExtractObjToList(key string, listObj runtime.Object) error
if err != nil {
return err
}
key = h.PrefixEtcdKey(key)
response, err := h.Client.Get(key, false, false)
if err != nil {
if IsEtcdNotFound(err) {
......@@ -185,6 +191,7 @@ func (h *EtcdHelper) ExtractObjToList(key string, listObj runtime.Object) error
// a zero object of the requested type, or an error, depending on ignoreNotFound. Treats
// empty responses and nil response nodes exactly like a not found error.
func (h *EtcdHelper) ExtractObj(key string, objPtr runtime.Object, ignoreNotFound bool) error {
key = h.PrefixEtcdKey(key)
_, _, err := h.bodyAndExtractObj(key, objPtr, ignoreNotFound)
return err
}
......@@ -233,6 +240,7 @@ func (h *EtcdHelper) extractObj(response *etcd.Response, inErr error, objPtr run
// and 0 means forever. If no error is returned and out is not nil, out will be set to the read value
// from etcd.
func (h *EtcdHelper) CreateObj(key string, obj, out runtime.Object, ttl uint64) error {
key = h.PrefixEtcdKey(key)
data, err := h.Codec.Encode(obj)
if err != nil {
return err
......@@ -242,6 +250,7 @@ func (h *EtcdHelper) CreateObj(key string, obj, out runtime.Object, ttl uint64)
return errors.New("resourceVersion may not be set on objects to be created")
}
}
response, err := h.Client.Create(key, string(data), ttl)
if err != nil {
return err
......@@ -257,15 +266,18 @@ func (h *EtcdHelper) CreateObj(key string, obj, out runtime.Object, ttl uint64)
// Delete removes the specified key.
func (h *EtcdHelper) Delete(key string, recursive bool) error {
key = h.PrefixEtcdKey(key)
_, err := h.Client.Delete(key, recursive)
return err
}
// DeleteObj removes the specified key and returns the value that existed at that spot.
func (h *EtcdHelper) DeleteObj(key string, out runtime.Object) error {
key = h.PrefixEtcdKey(key)
if _, err := conversion.EnforcePtr(out); err != nil {
panic("unable to convert output object to pointer")
}
response, err := h.Client.Delete(key, false)
if !IsEtcdNotFound(err) {
// if the object that existed prior to the delete is returned by etcd, update out.
......@@ -285,6 +297,7 @@ func (h *EtcdHelper) SetObj(key string, obj, out runtime.Object, ttl uint64) err
if err != nil {
return err
}
key = h.PrefixEtcdKey(key)
create := true
if h.Versioner != nil {
......@@ -346,6 +359,7 @@ func (h *EtcdHelper) GuaranteedUpdate(key string, ptrToType runtime.Object, igno
// Panic is appropriate, because this is a programming error.
panic("need ptr to type")
}
key = h.PrefixEtcdKey(key)
for {
obj := reflect.New(v.Type()).Interface().(runtime.Object)
origBody, index, err := h.bodyAndExtractObj(key, obj, ignoreNotFound)
......@@ -386,6 +400,13 @@ func (h *EtcdHelper) GuaranteedUpdate(key string, ptrToType runtime.Object, igno
}
}
func (h *EtcdHelper) PrefixEtcdKey(key string) string {
if strings.HasPrefix(key, path.Join("/", h.PathPrefix)) {
return key
}
return path.Join("/", h.PathPrefix, key)
}
// GetEtcdVersion performs a version check against the provided Etcd server, returning a triplet
// of the release version, internal version, and error (if any).
func GetEtcdVersion(host string) (releaseVersion, internalVersion string, err error) {
......
......@@ -71,6 +71,7 @@ func ParseWatchResourceVersion(resourceVersion, kind string) (uint64, error) {
// watch.Interface. resourceVersion may be used to specify what version to begin
// watching (e.g., for reconnecting without missing any updates).
func (h *EtcdHelper) WatchList(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
key = h.PrefixEtcdKey(key)
w := newEtcdWatcher(true, exceptKey(key), filter, h.Codec, h.Versioner, nil)
go w.etcdWatch(h.Client, key, resourceVersion)
return w, nil
......@@ -80,6 +81,7 @@ func (h *EtcdHelper) WatchList(key string, resourceVersion uint64, filter Filter
// API objects and sent down the returned watch.Interface.
// Errors will be sent down the channel.
func (h *EtcdHelper) Watch(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
key = h.PrefixEtcdKey(key)
w := newEtcdWatcher(false, nil, filter, h.Codec, h.Versioner, nil)
go w.etcdWatch(h.Client, key, resourceVersion)
return w, nil
......@@ -102,6 +104,7 @@ func (h *EtcdHelper) Watch(key string, resourceVersion uint64, filter FilterFunc
//
// Errors will be sent down the channel.
func (h *EtcdHelper) WatchAndTransform(key string, resourceVersion uint64, transform TransformFunc) watch.Interface {
key = h.PrefixEtcdKey(key)
w := newEtcdWatcher(false, nil, Everything, h.Codec, h.Versioner, transform)
go w.etcdWatch(h.Client, key, resourceVersion)
return w
......
......@@ -25,6 +25,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
"github.com/coreos/go-etcd/etcd"
)
......@@ -205,7 +206,7 @@ func TestWatchEtcdError(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
fakeClient.expectNotFoundGetSet["/some/key"] = struct{}{}
fakeClient.WatchImmediateError = fmt.Errorf("immediate error")
h := EtcdHelper{fakeClient, codec, versioner}
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.Watch("/some/key", 4, Everything)
if err != nil {
......@@ -232,10 +233,12 @@ func TestWatchEtcdError(t *testing.T) {
func TestWatch(t *testing.T) {
codec := latest.Codec
fakeClient := NewFakeEtcdClient(t)
fakeClient.expectNotFoundGetSet["/some/key"] = struct{}{}
h := EtcdHelper{fakeClient, codec, versioner}
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient.expectNotFoundGetSet[prefixedKey] = struct{}{}
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.Watch("/some/key", 0, Everything)
watching, err := h.Watch(key, 0, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -300,6 +303,8 @@ func makeSubsets(ip string, port int) []api.EndpointSubset {
func TestWatchEtcdState(t *testing.T) {
codec := latest.Codec
baseKey := "/somekey/foo"
prefixedKey := etcdtest.AddPrefix(baseKey)
type T struct {
Type watch.EventType
Endpoints []api.EndpointSubset
......@@ -357,7 +362,7 @@ func TestWatchEtcdState(t *testing.T) {
},
"from initial state": {
Initial: map[string]EtcdResponseWithError{
"/somekey/foo": {
prefixedKey: {
R: &etcd.Response{
Action: "get",
Node: &etcd.Node{
......@@ -406,8 +411,9 @@ func TestWatchEtcdState(t *testing.T) {
for key, value := range testCase.Initial {
fakeClient.Data[key] = value
}
h := EtcdHelper{fakeClient, codec, versioner}
watching, err := h.Watch("/somekey/foo", testCase.From, Everything)
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.Watch(baseKey, testCase.From, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -476,10 +482,12 @@ func TestWatchFromZeroIndex(t *testing.T) {
for k, testCase := range testCases {
fakeClient := NewFakeEtcdClient(t)
fakeClient.Data["/some/key"] = testCase.Response
h := EtcdHelper{fakeClient, codec, versioner}
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient.Data[prefixedKey] = testCase.Response
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.Watch("/some/key", 0, Everything)
watching, err := h.Watch(key, 0, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -512,9 +520,10 @@ func TestWatchFromZeroIndex(t *testing.T) {
func TestWatchListFromZeroIndex(t *testing.T) {
codec := latest.Codec
pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient := NewFakeEtcdClient(t)
fakeClient.Data["/some/key"] = EtcdResponseWithError{
fakeClient.Data[prefixedKey] = EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Dir: true,
......@@ -537,9 +546,9 @@ func TestWatchListFromZeroIndex(t *testing.T) {
EtcdIndex: 3,
},
}
h := EtcdHelper{fakeClient, codec, versioner}
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.WatchList("/some/key", 0, Everything)
watching, err := h.WatchList(key, 0, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -573,11 +582,13 @@ func TestWatchListFromZeroIndex(t *testing.T) {
func TestWatchListIgnoresRootKey(t *testing.T) {
codec := latest.Codec
pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient := NewFakeEtcdClient(t)
h := EtcdHelper{fakeClient, codec, versioner}
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.WatchList("/some/key", 1, Everything)
watching, err := h.WatchList(key, 1, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -587,7 +598,7 @@ func TestWatchListIgnoresRootKey(t *testing.T) {
fakeClient.WatchResponse <- &etcd.Response{
Action: "delete",
PrevNode: &etcd.Node{
Key: "/some/key",
Key: prefixedKey,
Value: runtime.EncodeOrDie(codec, pod),
CreatedIndex: 1,
ModifiedIndex: 1,
......@@ -598,7 +609,7 @@ func TestWatchListIgnoresRootKey(t *testing.T) {
fakeClient.WatchResponse <- &etcd.Response{
Action: "delete",
PrevNode: &etcd.Node{
Key: "/some/key",
Key: prefixedKey,
Value: "",
CreatedIndex: 1,
ModifiedIndex: 1,
......@@ -617,7 +628,9 @@ func TestWatchListIgnoresRootKey(t *testing.T) {
func TestWatchFromNotFound(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
fakeClient.Data["/some/key"] = EtcdResponseWithError{
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient.Data[prefixedKey] = EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
},
......@@ -626,13 +639,12 @@ func TestWatchFromNotFound(t *testing.T) {
ErrorCode: 100,
},
}
h := EtcdHelper{fakeClient, codec, versioner}
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.Watch("/some/key", 0, Everything)
watching, err := h.Watch(key, 0, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
fakeClient.WaitForWatchCompletion()
if fakeClient.WatchIndex != 3 {
t.Errorf("Expected client to wait for %d, got %#v", 3, fakeClient)
......@@ -643,7 +655,9 @@ func TestWatchFromNotFound(t *testing.T) {
func TestWatchFromOtherError(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
fakeClient.Data["/some/key"] = EtcdResponseWithError{
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient.Data[prefixedKey] = EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
},
......@@ -652,9 +666,8 @@ func TestWatchFromOtherError(t *testing.T) {
ErrorCode: 101,
},
}
h := EtcdHelper{fakeClient, codec, versioner}
watching, err := h.Watch("/some/key", 0, Everything)
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
watching, err := h.Watch(key, 0, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......@@ -683,11 +696,13 @@ func TestWatchFromOtherError(t *testing.T) {
func TestWatchPurposefulShutdown(t *testing.T) {
fakeClient := NewFakeEtcdClient(t)
h := EtcdHelper{fakeClient, codec, versioner}
fakeClient.expectNotFoundGetSet["/some/key"] = struct{}{}
h := EtcdHelper{fakeClient, codec, versioner, etcdtest.PathPrefix()}
key := "/some/key"
prefixedKey := etcdtest.AddPrefix(key)
fakeClient.expectNotFoundGetSet[prefixedKey] = struct{}{}
// Test purposeful shutdown
watching, err := h.Watch("/some/key", 0, Everything)
watching, err := h.Watch(key, 0, Everything)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
......
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etcdtest
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etcdtest
import (
"os"
"path"
)
// Returns the prefix set via the ETCD_PREFIX environment variable (if any).
func PathPrefix() string {
return path.Join("/", os.Getenv("ETCD_PREFIX"))
}
// Adds the ETCD_PREFIX to the provided key
func AddPrefix(in string) string {
return path.Join(PathPrefix(), in)
}
......@@ -46,6 +46,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/auth/authenticator/token/tokentest"
)
......@@ -377,7 +378,7 @@ func TestAuthModeAlwaysAllow(t *testing.T) {
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -516,8 +517,7 @@ func TestAuthModeAlwaysDeny(t *testing.T) {
deleteAllEtcdKeys()
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -583,8 +583,7 @@ func TestAliceNotForbiddenOrUnauthorized(t *testing.T) {
// This file has alice and bob in it.
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -672,8 +671,7 @@ func TestBobIsForbidden(t *testing.T) {
// This file has alice and bob in it.
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -733,8 +731,7 @@ func TestUnknownUserIsUnauthorized(t *testing.T) {
// This file has alice and bob in it.
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -810,8 +807,7 @@ func TestNamespaceAuthorization(t *testing.T) {
deleteAllEtcdKeys()
// This file has alice and bob in it.
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -925,8 +921,7 @@ func TestKindAuthorization(t *testing.T) {
// This file has alice and bob in it.
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......@@ -1028,8 +1023,7 @@ func TestReadOnlyAuthorization(t *testing.T) {
// This file has alice and bob in it.
// Set up a master
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......
......@@ -26,6 +26,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
......@@ -92,8 +93,9 @@ func TestExtractObj(t *testing.T) {
func TestWatch(t *testing.T) {
client := newEtcdClient()
helper := tools.NewEtcdHelper(client, testapi.Codec())
helper := tools.NewEtcdHelper(client, testapi.Codec(), etcdtest.PathPrefix())
withEtcdKey(func(key string) {
key = etcdtest.AddPrefix(key)
resp, err := client.Set(key, runtime.EncodeOrDie(testapi.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0)
if err != nil {
t.Fatalf("unexpected error: %v", err)
......
......@@ -33,6 +33,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler"
......@@ -45,7 +46,7 @@ func init() {
}
func TestUnschedulableNodes(t *testing.T) {
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("Couldn't create etcd helper: %v", err)
}
......
......@@ -30,6 +30,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
)
......@@ -50,7 +51,7 @@ func deleteSecretOrErrorf(t *testing.T, c *client.Client, ns, name string) {
// TestSecrets tests apiserver-side behavior of creation of secret objects and their use by pods.
func TestSecrets(t *testing.T) {
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......
......@@ -29,6 +29,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
"github.com/coreos/go-etcd/etcd"
......@@ -66,7 +67,7 @@ func deleteAllEtcdKeys() {
}
func runAMaster(t *testing.T) (*master.Master, *httptest.Server) {
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version())
helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment