// DefaultKeyFunctions sets the default behavior for storage key generation onto a Store. func DefaultKeyFunctions(store *registry.Store, prefix string, isNamespaced bool) { if isNamespaced { if store.KeyRootFunc == nil { store.KeyRootFunc = func(ctx kapi.Context) string { return registry.NamespaceKeyRootFunc(ctx, prefix) } } if store.KeyFunc == nil { store.KeyFunc = func(ctx kapi.Context, name string) (string, error) { return registry.NamespaceKeyFunc(ctx, prefix, name) } } } else { if store.KeyRootFunc == nil { store.KeyRootFunc = func(ctx kapi.Context) string { return prefix } } if store.KeyFunc == nil { store.KeyFunc = func(ctx kapi.Context, name string) (string, error) { return registry.NoNamespaceKeyFunc(ctx, prefix, name) } } } }
// NewREST returns a new REST. func NewREST(optsGetter restoptions.Getter, defaultRegistry api.DefaultRegistry, subjectAccessReviewRegistry subjectaccessreview.Registry, limitVerifier imageadmission.LimitVerifier) (*REST, *StatusREST, *InternalREST, error) { prefix := "/imagestreams" store := registry.Store{ NewFunc: func() runtime.Object { return &api.ImageStream{} }, // NewListFunc returns an object capable of storing results of an etcd list. NewListFunc: func() runtime.Object { return &api.ImageStreamList{} }, // Produces a path that etcd understands, to the root of the resource // by combining the namespace in the context with the given prefix. KeyRootFunc: func(ctx kapi.Context) string { return registry.NamespaceKeyRootFunc(ctx, prefix) }, // Produces a path that etcd understands, to the resource by combining // the namespace in the context with the given prefix KeyFunc: func(ctx kapi.Context, name string) (string, error) { return registry.NamespaceKeyFunc(ctx, prefix, name) }, // Retrieve the name field of an image ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.ImageStream).Name, nil }, // Used to match objects based on labels/fields for list and watch PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { return imagestream.MatchImageStream(label, field) }, QualifiedResource: api.Resource("imagestreams"), ReturnDeletedObject: false, } strategy := imagestream.NewStrategy(defaultRegistry, subjectAccessReviewRegistry, limitVerifier) rest := &REST{Store: &store, subjectAccessReviewRegistry: subjectAccessReviewRegistry} strategy.ImageStreamGetter = rest store.CreateStrategy = strategy store.UpdateStrategy = strategy store.Decorator = strategy.Decorate if err := restoptions.ApplyOptions(optsGetter, &store, prefix); err != nil { return nil, nil, nil, err } statusStore := store statusStore.Decorator = nil statusStore.CreateStrategy = nil statusStore.UpdateStrategy = imagestream.NewStatusStrategy(strategy) internalStore := store internalStrategy := imagestream.NewInternalStrategy(strategy) internalStore.Decorator = nil internalStore.CreateStrategy = internalStrategy internalStore.UpdateStrategy = internalStrategy return rest, &StatusREST{store: &statusStore}, &InternalREST{store: &internalStore}, nil }
// NewREST returns a new REST. func NewREST(optsGetter restoptions.Getter, defaultRegistry api.DefaultRegistry, subjectAccessReviewRegistry subjectaccessreview.Registry, limitVerifier imageadmission.LimitVerifier) (*REST, *StatusREST, *InternalREST, error) { store := registry.Store{ NewFunc: func() runtime.Object { return &api.ImageStream{} }, // NewListFunc returns an object capable of storing results of an etcd list. NewListFunc: func() runtime.Object { return &api.ImageStreamList{} }, // Retrieve the name field of an image ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.ImageStream).Name, nil }, // Used to match objects based on labels/fields for list and watch PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return imagestream.Matcher(label, field) }, QualifiedResource: api.Resource("imagestreams"), ReturnDeletedObject: false, } rest := &REST{ Store: &store, subjectAccessReviewRegistry: subjectAccessReviewRegistry, } // strategy must be able to load image streams across namespaces during tag verification strategy := imagestream.NewStrategy(defaultRegistry, subjectAccessReviewRegistry, limitVerifier, rest) store.CreateStrategy = strategy store.UpdateStrategy = strategy store.Decorator = strategy.Decorate if err := restoptions.ApplyOptions(optsGetter, &store, true, storage.NoTriggerPublisher); err != nil { return nil, nil, nil, err } statusStrategy := imagestream.NewStatusStrategy(strategy) statusStore := store statusStore.Decorator = nil statusStore.CreateStrategy = nil statusStore.UpdateStrategy = statusStrategy statusREST := &StatusREST{store: &statusStore} internalStore := store internalStrategy := imagestream.NewInternalStrategy(strategy) internalStore.Decorator = nil internalStore.CreateStrategy = internalStrategy internalStore.UpdateStrategy = internalStrategy internalREST := &InternalREST{store: &internalStore} return rest, statusREST, internalREST, nil }
// ApplyOptions updates the given generic storage from the provided rest options // TODO: remove need for etcdPrefix once Decorator interface is refactored upstream func ApplyOptions(optsGetter Getter, store *registry.Store, isNamespaced bool, triggerFn storage.TriggerPublisherFunc) error { if store.QualifiedResource.Empty() { return fmt.Errorf("store must have a non-empty qualified resource") } if store.NewFunc == nil { return fmt.Errorf("store for %s must have NewFunc set", store.QualifiedResource.String()) } if store.NewListFunc == nil { return fmt.Errorf("store for %s must have NewListFunc set", store.QualifiedResource.String()) } if store.CreateStrategy == nil { return fmt.Errorf("store for %s must have CreateStrategy set", store.QualifiedResource.String()) } opts, err := optsGetter.GetRESTOptions(store.QualifiedResource) if err != nil { return fmt.Errorf("error building RESTOptions for %s store: %v", store.QualifiedResource.String(), err) } // Resource prefix must come from the underlying factory prefix := opts.ResourcePrefix if !strings.HasPrefix(prefix, "/") { prefix = "/" + prefix } DefaultKeyFunctions(store, prefix, isNamespaced) store.DeleteCollectionWorkers = opts.DeleteCollectionWorkers store.Storage, _ = opts.Decorator( opts.StorageConfig, UseConfiguredCacheSize, store.NewFunc(), prefix, store.CreateStrategy, store.NewListFunc, triggerFn, ) return nil }
// ApplyOptions updates the given generic storage from the provided rest options // TODO: remove need for etcdPrefix once Decorator interface is refactored upstream func ApplyOptions(optsGetter Getter, store *registry.Store, etcdPrefix string) error { if store.QualifiedResource.IsEmpty() { return fmt.Errorf("store must have a non-empty qualified resource") } if store.NewFunc == nil { return fmt.Errorf("store for %s must have NewFunc set", store.QualifiedResource.String()) } if store.NewListFunc == nil { return fmt.Errorf("store for %s must have NewListFunc set", store.QualifiedResource.String()) } if store.CreateStrategy == nil { return fmt.Errorf("store for %s must have CreateStrategy set", store.QualifiedResource.String()) } opts, err := optsGetter.GetRESTOptions(store.QualifiedResource) if err != nil { return fmt.Errorf("error building RESTOptions for %s store: %v", store.QualifiedResource.String(), err) } store.DeleteCollectionWorkers = opts.DeleteCollectionWorkers store.Storage = opts.Decorator(opts.Storage, UseConfiguredCacheSize, store.NewFunc(), etcdPrefix, store.CreateStrategy, store.NewListFunc) return nil }
func NewREST(store registry.Store, oc client.Interface, kc kclient.Interface, decoder runtime.Decoder, admission admission.Interface) *REST { store.UpdateStrategy = Strategy return &REST{store: &store, isn: oc, rn: kc, decoder: decoder, admit: admission} }