// Creates a cacher based given storageConfig. func StorageWithCacher( storageConfig *storagebackend.Config, capacity int, objectType runtime.Object, resourcePrefix string, scopeStrategy rest.NamespaceScopedStrategy, newListFunc func() runtime.Object, triggerFunc storage.TriggerPublisherFunc) storage.Interface { // TODO: we would change this later to make storage always have cacher and hide low level KV layer inside. // Currently it has two layers of same storage interface -- cacher and low level kv. cacherConfig := storage.CacherConfig{ CacheCapacity: capacity, Storage: generic.NewRawStorage(storageConfig), Versioner: etcdstorage.APIObjectVersioner{}, Type: objectType, ResourcePrefix: resourcePrefix, NewListFunc: newListFunc, TriggerPublisherFunc: triggerFunc, Codec: storageConfig.Codec, } if scopeStrategy.NamespaceScoped() { cacherConfig.KeyFunc = func(obj runtime.Object) (string, error) { return storage.NamespaceKeyFunc(resourcePrefix, obj) } } else { cacherConfig.KeyFunc = func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(resourcePrefix, obj) } } return storage.NewCacherFromConfig(cacherConfig) }
// Creates a cacher on top of the given 'storageInterface'. func StorageWithCacher( storageInterface storage.Interface, capacity int, objectType runtime.Object, resourcePrefix string, scopeStrategy rest.NamespaceScopedStrategy, newListFunc func() runtime.Object) storage.Interface { config := storage.CacherConfig{ CacheCapacity: capacity, Storage: storageInterface, Versioner: etcdstorage.APIObjectVersioner{}, Type: objectType, ResourcePrefix: resourcePrefix, NewListFunc: newListFunc, } if scopeStrategy.NamespaceScoped() { config.KeyFunc = func(obj runtime.Object) (string, error) { return storage.NamespaceKeyFunc(resourcePrefix, obj) } } else { config.KeyFunc = func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(resourcePrefix, obj) } } return storage.NewCacherFromConfig(config) }
func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (*etcdtesting.EtcdTestServer, *Store) { podPrefix := "/pods" server, sc := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} sc.Codec = testapi.Default.StorageCodec() s, err := factory.Create(*sc) if err != nil { t.Fatalf("Error creating storage: %v", err) } if hasCacheEnabled { config := storage.CacherConfig{ CacheCapacity: 10, Storage: s, Versioner: etcdstorage.APIObjectVersioner{}, Type: &api.Pod{}, ResourcePrefix: podPrefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(podPrefix, obj) }, NewListFunc: func() runtime.Object { return &api.PodList{} }, Codec: sc.Codec, } s = storage.NewCacherFromConfig(config) } return server, &Store{ NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, QualifiedResource: api.Resource("pods"), CreateStrategy: strategy, UpdateStrategy: strategy, DeleteStrategy: strategy, KeyRootFunc: func(ctx api.Context) string { return podPrefix }, KeyFunc: func(ctx api.Context, id string) (string, error) { if _, ok := api.NamespaceFrom(ctx); !ok { return "", fmt.Errorf("namespace is required") } return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod, ok := obj.(*api.Pod) if !ok { return nil, nil, fmt.Errorf("not a pod") } return labels.Set(pod.ObjectMeta.Labels), generic.ObjectMetaFieldsSet(pod.ObjectMeta, true), nil }, } }, Storage: s, } }
// NewREST returns a RESTStorage object that will work against nodes. func NewREST(s storage.Interface, useCacher bool, connection client.ConnectionInfoGetter) (*REST, *StatusREST) { prefix := "/minions" storageInterface := s if useCacher { config := storage.CacherConfig{ CacheCapacity: 1000, Storage: s, Type: &api.Node{}, ResourcePrefix: prefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(prefix, obj) }, NewListFunc: func() runtime.Object { return &api.NodeList{} }, } storageInterface = storage.NewCacher(config) } store := &etcdgeneric.Etcd{ NewFunc: func() runtime.Object { return &api.Node{} }, NewListFunc: func() runtime.Object { return &api.NodeList{} }, KeyRootFunc: func(ctx api.Context) string { return prefix }, KeyFunc: func(ctx api.Context, name string) (string, error) { return prefix + "/" + name, nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Node).Name, nil }, PredicateFunc: node.MatchNode, EndpointName: "node", CreateStrategy: node.Strategy, UpdateStrategy: node.Strategy, Storage: storageInterface, } statusStore := *store statusStore.UpdateStrategy = node.StatusStrategy return &REST{store, connection}, &StatusREST{store: &statusStore} }
func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (factory.DestroyFunc, *Store) { podPrefix := "/pods" server := etcdtesting.NewEtcdTestClientServer(t) strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} codec := testapi.Default.StorageCodec() s := etcdstorage.NewEtcdStorage(server.Client, codec, etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize) destroyFunc := func() { server.Terminate(t) } if hasCacheEnabled { config := storage.CacherConfig{ CacheCapacity: 10, Storage: s, Versioner: etcdstorage.APIObjectVersioner{}, Type: &api.Pod{}, ResourcePrefix: podPrefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(podPrefix, obj) }, NewListFunc: func() runtime.Object { return &api.PodList{} }, Codec: codec, } cacher := storage.NewCacherFromConfig(config) d := destroyFunc s = cacher destroyFunc = func() { cacher.Stop() d() } } return destroyFunc, &Store{ NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, QualifiedResource: api.Resource("pods"), CreateStrategy: strategy, UpdateStrategy: strategy, DeleteStrategy: strategy, KeyRootFunc: func(ctx api.Context) string { return podPrefix }, KeyFunc: func(ctx api.Context, id string) (string, error) { if _, ok := api.NamespaceFrom(ctx); !ok { return "", fmt.Errorf("namespace is required") } return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod, ok := obj.(*api.Pod) if !ok { return nil, nil, fmt.Errorf("not a pod") } return labels.Set(pod.ObjectMeta.Labels), generic.ObjectMetaFieldsSet(&pod.ObjectMeta, true), nil }, } }, Storage: s, } }