diff --git a/hack/import-restrictions.json b/hack/import-restrictions.json index 31b7a176d7ef..85013536927f 100644 --- a/hack/import-restrictions.json +++ b/hack/import-restrictions.json @@ -173,8 +173,7 @@ ], "allowedImportPackages": [ "vendor/k8s.io/kubernetes/pkg/api", - "vendor/k8s.io/kubernetes/pkg/api/v1", - "vendor/k8s.io/kubernetes/pkg/registry/core/namespace" + "vendor/k8s.io/kubernetes/pkg/api/v1" ] }, diff --git a/pkg/api/apihelpers/apitesting/fields.go b/pkg/api/apihelpers/apitesting/fields.go index e19f756f423f..8e3141eb800e 100644 --- a/pkg/api/apihelpers/apitesting/fields.go +++ b/pkg/api/apihelpers/apitesting/fields.go @@ -8,21 +8,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -func TestFieldLabelConversions(t *testing.T, scheme *runtime.Scheme, version, kind string, expectedLabels map[string]string, customLabels ...string) { - for label := range expectedLabels { - _, _, err := scheme.ConvertFieldLabel(version, kind, label, "") - if err != nil { - t.Errorf("No conversion registered for %s for %s %s", label, version, kind) - } - } - for _, label := range customLabels { - _, _, err := scheme.ConvertFieldLabel(version, kind, label, "") - if err != nil { - t.Errorf("No conversion registered for %s for %s %s", label, version, kind) - } - } -} - // FieldKeyCheck gathers information to check if the field key conversions are working correctly. It takes many parameters // in an attempt to reflect reality type FieldKeyCheck struct { @@ -46,6 +31,10 @@ func (f FieldKeyCheck) Check(t *testing.T) { t.Errorf("illegal field conversion %q for %v", externalFieldKey, f.Kind) continue } + // we get this by default + if internalFieldKey == "metadata.name" { + continue + } fieldSet := fields.Set{} if err := f.FieldKeyEvaluatorFn(internalObj, fieldSet); err != nil { diff --git a/pkg/api/apihelpers/fields.go b/pkg/api/apihelpers/fields.go index e3fbebb24c75..f600e5150754 100644 --- a/pkg/api/apihelpers/fields.go +++ b/pkg/api/apihelpers/fields.go @@ -1,8 +1,6 @@ package apihelpers import ( - "fmt" - "k8s.io/apimachinery/pkg/runtime" ) @@ -16,19 +14,3 @@ func LegacyMetaV1FieldSelectorConversionWithName(label, value string) (string, s return runtime.DefaultMetaV1FieldSelectorConversion(label, value) } } - -// GetFieldLabelConversionFunc returns a field label conversion func, which does the following: -// * returns overrideLabels[label], value, nil if the specified label exists in the overrideLabels map -// * returns label, value, nil if the specified label exists as a key in the supportedLabels map (values in this map are unused, it is intended to be a prototypical label/value map) -// * otherwise, returns an error -func GetFieldLabelConversionFunc(supportedLabels map[string]string, overrideLabels map[string]string) func(label, value string) (string, string, error) { - return func(label, value string) (string, string, error) { - if label, overridden := overrideLabels[label]; overridden { - return label, value, nil - } - if _, supported := supportedLabels[label]; supported { - return label, value, nil - } - return "", "", fmt.Errorf("field label not supported: %s", label) - } -} diff --git a/pkg/authorization/apis/authorization/fields.go b/pkg/authorization/apis/authorization/fields.go index 16c3b92d08b5..1ae4d944b2da 100644 --- a/pkg/authorization/apis/authorization/fields.go +++ b/pkg/authorization/apis/authorization/fields.go @@ -1,13 +1,17 @@ package authorization -import "k8s.io/apimachinery/pkg/fields" +import ( + "fmt" -// PolicyBindingToSelectableFields returns a label set that represents the object -// changes to the returned keys require registering conversions for existing versions using Scheme.AddFieldLabelConversionFunc -func PolicyBindingToSelectableFields(policyBinding *PolicyBinding) fields.Set { - return fields.Set{ - "metadata.name": policyBinding.Name, - "metadata.namespace": policyBinding.Namespace, - "policyRef.namespace": policyBinding.PolicyRef.Namespace, + "k8s.io/apimachinery/pkg/fields" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func PolicyBindingFieldSelector(obj runtime.Object, fieldSet fields.Set) error { + policyBinding, ok := obj.(*PolicyBinding) + if !ok { + return fmt.Errorf("%T not a PolicyBinding", obj) } + fieldSet["policyRef.namespace"] = policyBinding.PolicyRef.Namespace + return nil } diff --git a/pkg/authorization/apis/authorization/v1/conversion.go b/pkg/authorization/apis/authorization/v1/conversion.go index 7242af292b7c..8497f1848483 100644 --- a/pkg/authorization/apis/authorization/v1/conversion.go +++ b/pkg/authorization/apis/authorization/v1/conversion.go @@ -394,15 +394,32 @@ func addConversionFuncs(scheme *runtime.Scheme) error { return err } - if err := scheme.AddFieldLabelConversionFunc("v1", "PolicyBinding", - apihelpers.GetFieldLabelConversionFunc(newer.PolicyBindingToSelectableFields(&newer.PolicyBinding{}), nil), - ); err != nil { + return nil +} + +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "PolicyBinding", legacyPolicyBindingFieldSelectorKeyConversionFunc); err != nil { return err } + return nil +} +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { return nil } +// because field selectors can vary in support by version they are exposed under, we have one function for each +// groupVersion we're registering for + +func legacyPolicyBindingFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "policyRef.namespace": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + var _ runtime.NestedObjectDecoder = &PolicyRule{} var _ runtime.NestedObjectEncoder = &PolicyRule{} diff --git a/pkg/authorization/apis/authorization/v1/conversion_test.go b/pkg/authorization/apis/authorization/v1/conversion_test.go index 1ecd6bac1a05..fcbf3ae57186 100644 --- a/pkg/authorization/apis/authorization/v1/conversion_test.go +++ b/pkg/authorization/apis/authorization/v1/conversion_test.go @@ -10,12 +10,11 @@ import ( ) func TestFieldSelectorConversions(t *testing.T) { - converter := runtime.NewScheme() - LegacySchemeBuilder.AddToScheme(converter) - - apitesting.TestFieldLabelConversions(t, converter, "v1", "PolicyBinding", - // Ensure all currently returned labels are supported - authorizationapi.PolicyBindingToSelectableFields(&authorizationapi.PolicyBinding{}), - ) - + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, authorizationapi.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("PolicyBinding"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"policyRef.namespace"}, + FieldKeyEvaluatorFn: authorizationapi.PolicyBindingFieldSelector, + }.Check(t) } diff --git a/pkg/authorization/apis/authorization/v1/register.go b/pkg/authorization/apis/authorization/v1/register.go index db42eec11958..8a575bba0da8 100644 --- a/pkg/authorization/apis/authorization/v1/register.go +++ b/pkg/authorization/apis/authorization/v1/register.go @@ -15,10 +15,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, RegisterDefaults) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, addLegacyFieldSelectorKeyConversions, RegisterDefaults) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, RegisterDefaults) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addFieldSelectorKeyConversions, RegisterDefaults) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/build/apis/build/fields.go b/pkg/build/apis/build/fields.go index 741bbf01f260..49ab7ba5e449 100644 --- a/pkg/build/apis/build/fields.go +++ b/pkg/build/apis/build/fields.go @@ -1,14 +1,19 @@ package build -import "k8s.io/apimachinery/pkg/fields" - -// BuildToSelectableFields returns a label set that represents the object -// changes to the returned keys require registering conversions for existing versions using Scheme.AddFieldLabelConversionFunc -func BuildToSelectableFields(build *Build) fields.Set { - return fields.Set{ - "metadata.name": build.Name, - "metadata.namespace": build.Namespace, - "status": string(build.Status.Phase), - "podName": GetBuildPodName(build), +import ( + "fmt" + + "k8s.io/apimachinery/pkg/fields" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func BuildFieldSelector(obj runtime.Object, fieldSet fields.Set) error { + build, ok := obj.(*Build) + if !ok { + return fmt.Errorf("%T not a Build", obj) } + fieldSet["status"] = string(build.Status.Phase) + fieldSet["podName"] = GetBuildPodName(build) + + return nil } diff --git a/pkg/build/apis/build/v1/conversion.go b/pkg/build/apis/build/v1/conversion.go index 3b326a5a7d4c..d057dafd66e6 100644 --- a/pkg/build/apis/build/v1/conversion.go +++ b/pkg/build/apis/build/v1/conversion.go @@ -174,24 +174,45 @@ func addConversionFuncs(scheme *runtime.Scheme) error { return err } - if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Build", - apihelpers.GetFieldLabelConversionFunc(newer.BuildToSelectableFields(&newer.Build{}), nil), - ); err != nil { - return err - } - return nil } -func addLegacyFieldLabelConversions(scheme *runtime.Scheme) error { - if err := scheme.AddFieldLabelConversionFunc("v1", "Build", - apihelpers.GetFieldLabelConversionFunc(newer.BuildToSelectableFields(&newer.Build{}), map[string]string{"name": "metadata.name"}), - ); err != nil { +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "Build", legacyBuildFieldSelectorKeyConversionFunc); err != nil { return err } + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "BuildConfig", apihelpers.LegacyMetaV1FieldSelectorConversionWithName); err != nil { + return err + } + return nil +} - if err := scheme.AddFieldLabelConversionFunc("v1", "BuildConfig", apihelpers.LegacyMetaV1FieldSelectorConversionWithName); err != nil { +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Build", buildFieldSelectorKeyConversionFunc); err != nil { return err } return nil } + +// because field selectors can vary in support by version they are exposed under, we have one function for each +// groupVersion we're registering for + +func legacyBuildFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "status", + "podName": + return label, value, nil + default: + return apihelpers.LegacyMetaV1FieldSelectorConversionWithName(label, value) + } +} + +func buildFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "status", + "podName": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} diff --git a/pkg/build/apis/build/v1/conversion_test.go b/pkg/build/apis/build/v1/conversion_test.go index 5ffc9a33dab1..04bb2ebc6e21 100644 --- a/pkg/build/apis/build/v1/conversion_test.go +++ b/pkg/build/apis/build/v1/conversion_test.go @@ -16,15 +16,29 @@ import ( var Convert = knewer.Scheme.Convert func TestFieldSelectorConversions(t *testing.T) { - converter := runtime.NewScheme() - LegacySchemeBuilder.AddToScheme(converter) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, newer.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("Build"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"name", "status", "podName"}, + FieldKeyEvaluatorFn: newer.BuildFieldSelector, + }.Check(t) + + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, newer.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("BuildConfig"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"name"}, + }.Check(t) - apitesting.TestFieldLabelConversions(t, converter, "v1", "Build", - // Ensure all currently returned labels are supported - newer.BuildToSelectableFields(&newer.Build{}), + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{SchemeBuilder.AddToScheme, newer.SchemeBuilder.AddToScheme}, + Kind: SchemeGroupVersion.WithKind("Build"), // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "name", "status", "podName", - ) + AllowedExternalFieldKeys: []string{"status", "podName"}, + FieldKeyEvaluatorFn: newer.BuildFieldSelector, + }.Check(t) + } func TestBinaryBuildRequestOptions(t *testing.T) { diff --git a/pkg/build/apis/build/v1/register.go b/pkg/build/apis/build/v1/register.go index fd3ac9dd810b..fc4a2fac8c32 100644 --- a/pkg/build/apis/build/v1/register.go +++ b/pkg/build/apis/build/v1/register.go @@ -13,10 +13,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, RegisterDefaults, addLegacyFieldLabelConversions) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, addLegacyFieldSelectorKeyConversions, RegisterDefaults) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, RegisterDefaults) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addFieldSelectorKeyConversions, RegisterDefaults) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/build/registry/build/etcd/etcd.go b/pkg/build/registry/build/etcd/etcd.go index 0802e188c257..21e61669c742 100644 --- a/pkg/build/registry/build/etcd/etcd.go +++ b/pkg/build/registry/build/etcd/etcd.go @@ -6,6 +6,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" buildapi "github.com/openshift/origin/pkg/build/apis/build" @@ -25,7 +26,6 @@ func NewREST(optsGetter restoptions.Getter) (*REST, *DetailsREST, error) { Copier: kapi.Scheme, NewFunc: func() runtime.Object { return &buildapi.Build{} }, NewListFunc: func() runtime.Object { return &buildapi.BuildList{} }, - PredicateFunc: build.Matcher, DefaultQualifiedResource: buildapi.Resource("builds"), CreateStrategy: build.Strategy, @@ -33,7 +33,10 @@ func NewREST(optsGetter restoptions.Getter) (*REST, *DetailsREST, error) { DeleteStrategy: build.Strategy, } - options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: build.GetAttrs} + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: storage.AttrFunc(storage.DefaultNamespaceScopedAttr).WithFieldMutation(buildapi.BuildFieldSelector), + } if err := store.CompleteWithOptions(options); err != nil { return nil, nil, err } diff --git a/pkg/build/registry/build/strategy.go b/pkg/build/registry/build/strategy.go index 5d2a7c6c95a5..341331defe03 100644 --- a/pkg/build/registry/build/strategy.go +++ b/pkg/build/registry/build/strategy.go @@ -1,16 +1,12 @@ package build import ( - "fmt" "reflect" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" apirequest "k8s.io/apiserver/pkg/endpoints/request" - kstorage "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" kapi "k8s.io/kubernetes/pkg/api" @@ -82,24 +78,6 @@ func (strategy) CheckGracefulDelete(obj runtime.Object, options *metav1.DeleteOp return false } -// GetAttrs returns labels and fields of a given object for filtering purposes -func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) { - build, ok := obj.(*buildapi.Build) - if !ok { - return nil, nil, false, fmt.Errorf("not a Build") - } - return labels.Set(build.ObjectMeta.Labels), buildapi.BuildToSelectableFields(build), build.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) kstorage.SelectionPredicate { - return kstorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - type detailsStrategy struct { strategy } diff --git a/pkg/image/apis/image/fields.go b/pkg/image/apis/image/fields.go index dc395aeb6f11..0463c5e71926 100644 --- a/pkg/image/apis/image/fields.go +++ b/pkg/image/apis/image/fields.go @@ -1,13 +1,19 @@ package image -import "k8s.io/apimachinery/pkg/fields" - -// ImageStreamToSelectableFields returns a label set that represents the object. -func ImageStreamToSelectableFields(ir *ImageStream) fields.Set { - return fields.Set{ - "metadata.name": ir.Name, - "metadata.namespace": ir.Namespace, - "spec.dockerImageRepository": ir.Spec.DockerImageRepository, - "status.dockerImageRepository": ir.Status.DockerImageRepository, +import ( + "fmt" + + "k8s.io/apimachinery/pkg/fields" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func ImageStreamSelector(obj runtime.Object, fieldSet fields.Set) error { + imageStream, ok := obj.(*ImageStream) + if !ok { + return fmt.Errorf("%T not an ImageStream", obj) } + fieldSet["spec.dockerImageRepository"] = imageStream.Spec.DockerImageRepository + fieldSet["status.dockerImageRepository"] = imageStream.Status.DockerImageRepository + + return nil } diff --git a/pkg/image/apis/image/v1/conversion.go b/pkg/image/apis/image/v1/conversion.go index 97bebe2a2e5e..1e1443ceb281 100644 --- a/pkg/image/apis/image/v1/conversion.go +++ b/pkg/image/apis/image/v1/conversion.go @@ -280,10 +280,42 @@ func addConversionFuncs(scheme *runtime.Scheme) error { return err } - if err := scheme.AddFieldLabelConversionFunc("v1", "ImageStream", - apihelpers.GetFieldLabelConversionFunc(newer.ImageStreamToSelectableFields(&newer.ImageStream{}), map[string]string{"name": "metadata.name"}), - ); err != nil { + return nil +} + +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "ImageStream", legacyImageStreamFieldSelectorKeyConversionFunc); err != nil { + return err + } + return nil +} + +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "ImageStream", imageStreamFieldSelectorKeyConversionFunc); err != nil { return err } return nil } + +// because field selectors can vary in support by version they are exposed under, we have one function for each +// groupVersion we're registering for + +func legacyImageStreamFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "spec.dockerImageRepository", + "status.dockerImageRepository": + return label, value, nil + default: + return apihelpers.LegacyMetaV1FieldSelectorConversionWithName(label, value) + } +} + +func imageStreamFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "spec.dockerImageRepository", + "status.dockerImageRepository": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} diff --git a/pkg/image/apis/image/v1/conversion_test.go b/pkg/image/apis/image/v1/conversion_test.go index bb5d68cd5759..75d2e07492ec 100644 --- a/pkg/image/apis/image/v1/conversion_test.go +++ b/pkg/image/apis/image/v1/conversion_test.go @@ -65,15 +65,21 @@ func TestRoundTripVersionedObject(t *testing.T) { } func TestFieldSelectors(t *testing.T) { - converter := runtime.NewScheme() - imageapiv1.LegacySchemeBuilder.AddToScheme(converter) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{imageapiv1.LegacySchemeBuilder.AddToScheme, newer.LegacySchemeBuilder.AddToScheme}, + Kind: imageapiv1.LegacySchemeGroupVersion.WithKind("ImageStream"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"name", "spec.dockerImageRepository", "status.dockerImageRepository"}, + FieldKeyEvaluatorFn: newer.ImageStreamSelector, + }.Check(t) - apitesting.TestFieldLabelConversions(t, converter, "v1", "ImageStream", - // Ensure all currently returned labels are supported - newer.ImageStreamToSelectableFields(&newer.ImageStream{}), + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{imageapiv1.SchemeBuilder.AddToScheme, newer.SchemeBuilder.AddToScheme}, + Kind: imageapiv1.SchemeGroupVersion.WithKind("ImageStream"), // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "name", "spec.dockerImageRepository", "status.dockerImageRepository", - ) + AllowedExternalFieldKeys: []string{"spec.dockerImageRepository", "status.dockerImageRepository"}, + FieldKeyEvaluatorFn: newer.ImageStreamSelector, + }.Check(t) } func TestImageImportSpecDefaulting(t *testing.T) { diff --git a/pkg/image/apis/image/v1/register.go b/pkg/image/apis/image/v1/register.go index 909a47f87a35..11368d16b7bd 100644 --- a/pkg/image/apis/image/v1/register.go +++ b/pkg/image/apis/image/v1/register.go @@ -19,10 +19,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, RegisterDefaults, docker10.AddToSchemeInCoreGroup, dockerpre012.AddToSchemeInCoreGroup) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, addLegacyFieldSelectorKeyConversions, RegisterDefaults, docker10.AddToSchemeInCoreGroup, dockerpre012.AddToSchemeInCoreGroup) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, RegisterDefaults, docker10.AddToScheme, dockerpre012.AddToScheme) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addFieldSelectorKeyConversions, RegisterDefaults, docker10.AddToScheme, dockerpre012.AddToScheme) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/image/registry/imagestream/etcd/etcd.go b/pkg/image/registry/imagestream/etcd/etcd.go index 574b6d1e7588..59d88639cef2 100644 --- a/pkg/image/registry/imagestream/etcd/etcd.go +++ b/pkg/image/registry/imagestream/etcd/etcd.go @@ -7,6 +7,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion" @@ -29,7 +30,6 @@ func NewREST(optsGetter restoptions.Getter, registryHostname imageapi.RegistryHo Copier: kapi.Scheme, NewFunc: func() runtime.Object { return &imageapi.ImageStream{} }, NewListFunc: func() runtime.Object { return &imageapi.ImageStreamList{} }, - PredicateFunc: imagestream.Matcher, DefaultQualifiedResource: imageapi.Resource("imagestreams"), } @@ -44,7 +44,10 @@ func NewREST(optsGetter restoptions.Getter, registryHostname imageapi.RegistryHo store.DeleteStrategy = strategy store.Decorator = strategy.Decorate - options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: imagestream.GetAttrs} + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: storage.AttrFunc(storage.DefaultNamespaceScopedAttr).WithFieldMutation(imageapi.ImageStreamSelector), + } if err := store.CompleteWithOptions(options); err != nil { return nil, nil, nil, err } diff --git a/pkg/image/registry/imagestream/strategy.go b/pkg/image/registry/imagestream/strategy.go index 5771a724995c..564b3748e429 100644 --- a/pkg/image/registry/imagestream/strategy.go +++ b/pkg/image/registry/imagestream/strategy.go @@ -7,14 +7,11 @@ import ( "github.com/golang/glog" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/authentication/user" apirequest "k8s.io/apiserver/pkg/endpoints/request" - kstorage "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" kapi "k8s.io/kubernetes/pkg/api" kapihelper "k8s.io/kubernetes/pkg/api/helper" @@ -598,29 +595,6 @@ func (s StatusStrategy) ValidateUpdate(ctx apirequest.Context, obj, old runtime. return errs } -// GetAttrs returns labels and fields of a given object for filtering purposes -func GetAttrs(o runtime.Object) (labels.Set, fields.Set, bool, error) { - obj, ok := o.(*imageapi.ImageStream) - if !ok { - return nil, nil, false, fmt.Errorf("not an ImageStream") - } - return labels.Set(obj.Labels), SelectableFields(obj), obj.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) kstorage.SelectionPredicate { - return kstorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *imageapi.ImageStream) fields.Set { - return imageapi.ImageStreamToSelectableFields(obj) -} - // InternalStrategy implements behavior for updating both the spec and status // of an image stream type InternalStrategy struct { diff --git a/pkg/oauth/apis/oauth/fields.go b/pkg/oauth/apis/oauth/fields.go index 6f6413b78945..f53cc65fd851 100644 --- a/pkg/oauth/apis/oauth/fields.go +++ b/pkg/oauth/apis/oauth/fields.go @@ -1,34 +1,42 @@ package oauth -import "k8s.io/apimachinery/pkg/fields" +import ( + "fmt" -// OAuthAccessTokenToSelectableFields returns a label set that represents the object -func OAuthAccessTokenToSelectableFields(obj *OAuthAccessToken) fields.Set { - return fields.Set{ - "metadata.name": obj.Name, - "clientName": obj.ClientName, - "userName": obj.UserName, - "userUID": obj.UserUID, - "authorizeToken": obj.AuthorizeToken, + "k8s.io/apimachinery/pkg/fields" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func OAuthAccessTokenFieldSelector(obj runtime.Object, fieldSet fields.Set) error { + oauthAccessToken, ok := obj.(*OAuthAccessToken) + if !ok { + return fmt.Errorf("%T not an OAuthAccessToken", obj) } + fieldSet["clientName"] = oauthAccessToken.ClientName + fieldSet["userName"] = oauthAccessToken.UserName + fieldSet["userUID"] = oauthAccessToken.UserUID + fieldSet["authorizeToken"] = oauthAccessToken.AuthorizeToken + return nil } -// OAuthAuthorizeTokenToSelectableFields returns a label set that represents the object -func OAuthAuthorizeTokenToSelectableFields(obj *OAuthAuthorizeToken) fields.Set { - return fields.Set{ - "metadata.name": obj.Name, - "clientName": obj.ClientName, - "userName": obj.UserName, - "userUID": obj.UserUID, +func OAuthAuthorizeTokenFieldSelector(obj runtime.Object, fieldSet fields.Set) error { + oauthAuthorizeToken, ok := obj.(*OAuthAuthorizeToken) + if !ok { + return fmt.Errorf("%T not an OAuthAuthorizeToken", obj) } + fieldSet["clientName"] = oauthAuthorizeToken.ClientName + fieldSet["userName"] = oauthAuthorizeToken.UserName + fieldSet["userUID"] = oauthAuthorizeToken.UserUID + return nil } -// OAuthClientAuthorizationToSelectableFields returns a label set that represents the object -func OAuthClientAuthorizationToSelectableFields(obj *OAuthClientAuthorization) fields.Set { - return fields.Set{ - "metadata.name": obj.Name, - "clientName": obj.ClientName, - "userName": obj.UserName, - "userUID": obj.UserUID, +func OAuthClientAuthorizationFieldSelector(obj runtime.Object, fieldSet fields.Set) error { + oauthClientAuthorization, ok := obj.(*OAuthClientAuthorization) + if !ok { + return fmt.Errorf("%T not an OAuthAuthorizeToken", obj) } + fieldSet["clientName"] = oauthClientAuthorization.ClientName + fieldSet["userName"] = oauthClientAuthorization.UserName + fieldSet["userUID"] = oauthClientAuthorization.UserUID + return nil } diff --git a/pkg/oauth/apis/oauth/v1/conversion.go b/pkg/oauth/apis/oauth/v1/conversion.go index c92899fbe988..69cc281d5806 100644 --- a/pkg/oauth/apis/oauth/v1/conversion.go +++ b/pkg/oauth/apis/oauth/v1/conversion.go @@ -2,28 +2,105 @@ package v1 import ( "k8s.io/apimachinery/pkg/runtime" - - "github.com/openshift/origin/pkg/api/apihelpers" - oauthapi "github.com/openshift/origin/pkg/oauth/apis/oauth" ) func addConversionFuncs(scheme *runtime.Scheme) error { - if err := scheme.AddFieldLabelConversionFunc("v1", "OAuthAccessToken", - apihelpers.GetFieldLabelConversionFunc(oauthapi.OAuthAccessTokenToSelectableFields(&oauthapi.OAuthAccessToken{}), nil), - ); err != nil { + return nil +} + +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "OAuthAccessToken", legacyOAuthAccessTokenFieldSelectorKeyConversionFunc); err != nil { return err } - - if err := scheme.AddFieldLabelConversionFunc("v1", "OAuthAuthorizeToken", - apihelpers.GetFieldLabelConversionFunc(oauthapi.OAuthAuthorizeTokenToSelectableFields(&oauthapi.OAuthAuthorizeToken{}), nil), - ); err != nil { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "OAuthAuthorizeToken", legacyOAuthAuthorizeTokenFieldSelectorKeyConversionFunc); err != nil { + return err + } + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "OAuthClientAuthorization", legacyOAuthClientAuthorizationFieldSelectorKeyConversionFunc); err != nil { return err } + return nil +} - if err := scheme.AddFieldLabelConversionFunc("v1", "OAuthClientAuthorization", - apihelpers.GetFieldLabelConversionFunc(oauthapi.OAuthClientAuthorizationToSelectableFields(&oauthapi.OAuthClientAuthorization{}), nil), - ); err != nil { +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "OAuthAccessToken", oauthAccessTokenFieldSelectorKeyConversionFunc); err != nil { + return err + } + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "OAuthAuthorizeToken", oauthAuthorizeTokenFieldSelectorKeyConversionFunc); err != nil { + return err + } + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "OAuthClientAuthorization", oauthClientAuthorizationFieldSelectorKeyConversionFunc); err != nil { return err } return nil } + +// because field selectors can vary in support by version they are exposed under, we have one function for each +// groupVersion we're registering for + +func legacyOAuthAccessTokenFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "clientName", + "userName", + "userUID", + "authorizeToken": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + +func oauthAccessTokenFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "clientName", + "userName", + "userUID", + "authorizeToken": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + +func legacyOAuthAuthorizeTokenFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "clientName", + "userName", + "userUID": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + +func oauthAuthorizeTokenFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "clientName", + "userName", + "userUID": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + +func legacyOAuthClientAuthorizationFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "clientName", + "userName", + "userUID": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + +func oauthClientAuthorizationFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "clientName", + "userName", + "userUID": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} diff --git a/pkg/oauth/apis/oauth/v1/conversion_test.go b/pkg/oauth/apis/oauth/v1/conversion_test.go index 4c7056b702da..63547b80edf2 100644 --- a/pkg/oauth/apis/oauth/v1/conversion_test.go +++ b/pkg/oauth/apis/oauth/v1/conversion_test.go @@ -10,27 +10,47 @@ import ( ) func TestFieldSelectorConversions(t *testing.T) { - converter := runtime.NewScheme() - LegacySchemeBuilder.AddToScheme(converter) - - apitesting.TestFieldLabelConversions(t, converter, "v1", "OAuthAccessToken", - // Ensure all currently returned labels are supported - oauthapi.OAuthAccessTokenToSelectableFields(&oauthapi.OAuthAccessToken{}), + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, oauthapi.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("OAuthAccessToken"), // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "clientName", "userName", "userUID", "authorizeToken", - ) - - apitesting.TestFieldLabelConversions(t, converter, "v1", "OAuthAuthorizeToken", - // Ensure all currently returned labels are supported - oauthapi.OAuthAuthorizeTokenToSelectableFields(&oauthapi.OAuthAuthorizeToken{}), + AllowedExternalFieldKeys: []string{"clientName", "userName", "userUID", "authorizeToken"}, + FieldKeyEvaluatorFn: oauthapi.OAuthAccessTokenFieldSelector, + }.Check(t) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, oauthapi.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("OAuthAuthorizeToken"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"clientName", "userName", "userUID"}, + FieldKeyEvaluatorFn: oauthapi.OAuthAuthorizeTokenFieldSelector, + }.Check(t) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, oauthapi.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("OAuthClientAuthorization"), // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "clientName", "userName", "userUID", - ) + AllowedExternalFieldKeys: []string{"clientName", "userName", "userUID"}, + FieldKeyEvaluatorFn: oauthapi.OAuthClientAuthorizationFieldSelector, + }.Check(t) - apitesting.TestFieldLabelConversions(t, converter, "v1", "OAuthClientAuthorization", - // Ensure all currently returned labels are supported - oauthapi.OAuthClientAuthorizationToSelectableFields(&oauthapi.OAuthClientAuthorization{}), + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{SchemeBuilder.AddToScheme, oauthapi.SchemeBuilder.AddToScheme}, + Kind: SchemeGroupVersion.WithKind("OAuthAccessToken"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"clientName", "userName", "userUID", "authorizeToken"}, + FieldKeyEvaluatorFn: oauthapi.OAuthAccessTokenFieldSelector, + }.Check(t) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{SchemeBuilder.AddToScheme, oauthapi.SchemeBuilder.AddToScheme}, + Kind: SchemeGroupVersion.WithKind("OAuthAuthorizeToken"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"clientName", "userName", "userUID"}, + FieldKeyEvaluatorFn: oauthapi.OAuthAuthorizeTokenFieldSelector, + }.Check(t) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{SchemeBuilder.AddToScheme, oauthapi.SchemeBuilder.AddToScheme}, + Kind: SchemeGroupVersion.WithKind("OAuthClientAuthorization"), // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "clientName", "userName", "userUID", - ) + AllowedExternalFieldKeys: []string{"clientName", "userName", "userUID"}, + FieldKeyEvaluatorFn: oauthapi.OAuthClientAuthorizationFieldSelector, + }.Check(t) } diff --git a/pkg/oauth/apis/oauth/v1/register.go b/pkg/oauth/apis/oauth/v1/register.go index c9e770fed3dd..63216ca1f197 100644 --- a/pkg/oauth/apis/oauth/v1/register.go +++ b/pkg/oauth/apis/oauth/v1/register.go @@ -16,10 +16,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, RegisterDefaults) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, addLegacyFieldSelectorKeyConversions, RegisterDefaults) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, RegisterDefaults) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addFieldSelectorKeyConversions, RegisterDefaults) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/oauth/registry/oauthaccesstoken/etcd/etcd.go b/pkg/oauth/registry/oauthaccesstoken/etcd/etcd.go index ddf0557e253a..a82db1486e91 100644 --- a/pkg/oauth/registry/oauthaccesstoken/etcd/etcd.go +++ b/pkg/oauth/registry/oauthaccesstoken/etcd/etcd.go @@ -31,7 +31,6 @@ func NewREST(optsGetter restoptions.Getter, clientGetter oauthclient.Getter, bac Copier: kapi.Scheme, NewFunc: func() runtime.Object { return &oauthapi.OAuthAccessToken{} }, NewListFunc: func() runtime.Object { return &oauthapi.OAuthAccessTokenList{} }, - PredicateFunc: oauthaccesstoken.Matcher, DefaultQualifiedResource: oauthapi.Resource("oauthaccesstokens"), TTLFunc: func(obj runtime.Object, existing uint64, update bool) (uint64, error) { @@ -45,7 +44,10 @@ func NewREST(optsGetter restoptions.Getter, clientGetter oauthclient.Getter, bac DeleteStrategy: strategy, } - options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: oauthaccesstoken.GetAttrs} + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: storage.AttrFunc(storage.DefaultNamespaceScopedAttr).WithFieldMutation(oauthapi.OAuthAccessTokenFieldSelector), + } if err := store.CompleteWithOptions(options); err != nil { return nil, err } diff --git a/pkg/oauth/registry/oauthaccesstoken/strategy.go b/pkg/oauth/registry/oauthaccesstoken/strategy.go index 2f839d281646..8ce80de43f6c 100644 --- a/pkg/oauth/registry/oauthaccesstoken/strategy.go +++ b/pkg/oauth/registry/oauthaccesstoken/strategy.go @@ -1,16 +1,11 @@ package oauthaccesstoken import ( - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" apirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - kstorage "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" scopeauthorizer "github.com/openshift/origin/pkg/authorization/authorizer/scope" @@ -86,26 +81,3 @@ func (strategy) AllowUnconditionalUpdate() bool { // Canonicalize normalizes the object after validation. func (strategy) Canonicalize(obj runtime.Object) { } - -// GetAttrs returns labels and fields of a given object for filtering purposes -func GetAttrs(o runtime.Object) (labels.Set, fields.Set, bool, error) { - obj, ok := o.(*oauthapi.OAuthAccessToken) - if !ok { - return nil, nil, false, fmt.Errorf("not an OAuthAccessToken") - } - return labels.Set(obj.Labels), SelectableFields(obj), obj.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) kstorage.SelectionPredicate { - return kstorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *oauthapi.OAuthAccessToken) fields.Set { - return oauthapi.OAuthAccessTokenToSelectableFields(obj) -} diff --git a/pkg/oauth/registry/oauthauthorizetoken/etcd/etcd.go b/pkg/oauth/registry/oauthauthorizetoken/etcd/etcd.go index 4beb84321f8d..74a580aeee3a 100644 --- a/pkg/oauth/registry/oauthauthorizetoken/etcd/etcd.go +++ b/pkg/oauth/registry/oauthauthorizetoken/etcd/etcd.go @@ -5,6 +5,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" oauthapi "github.com/openshift/origin/pkg/oauth/apis/oauth" @@ -27,7 +28,6 @@ func NewREST(optsGetter restoptions.Getter, clientGetter oauthclient.Getter) (*R Copier: kapi.Scheme, NewFunc: func() runtime.Object { return &oauthapi.OAuthAuthorizeToken{} }, NewListFunc: func() runtime.Object { return &oauthapi.OAuthAuthorizeTokenList{} }, - PredicateFunc: oauthauthorizetoken.Matcher, DefaultQualifiedResource: oauthapi.Resource("oauthauthorizetokens"), TTLFunc: func(obj runtime.Object, existing uint64, update bool) (uint64, error) { @@ -41,7 +41,10 @@ func NewREST(optsGetter restoptions.Getter, clientGetter oauthclient.Getter) (*R DeleteStrategy: strategy, } - options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: oauthauthorizetoken.GetAttrs} + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: storage.AttrFunc(storage.DefaultNamespaceScopedAttr).WithFieldMutation(oauthapi.OAuthAuthorizeTokenFieldSelector), + } if err := store.CompleteWithOptions(options); err != nil { return nil, err } diff --git a/pkg/oauth/registry/oauthauthorizetoken/strategy.go b/pkg/oauth/registry/oauthauthorizetoken/strategy.go index 7fc1e2be827a..02781cac4f3f 100644 --- a/pkg/oauth/registry/oauthauthorizetoken/strategy.go +++ b/pkg/oauth/registry/oauthauthorizetoken/strategy.go @@ -1,16 +1,11 @@ package oauthauthorizetoken import ( - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" apirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - kstorage "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" scopeauthorizer "github.com/openshift/origin/pkg/authorization/authorizer/scope" @@ -86,26 +81,3 @@ func (strategy) AllowCreateOnUpdate() bool { func (strategy) AllowUnconditionalUpdate() bool { return false } - -// GetAttrs returns labels and fields of a given object for filtering purposes -func GetAttrs(o runtime.Object) (labels.Set, fields.Set, bool, error) { - obj, ok := o.(*oauthapi.OAuthAuthorizeToken) - if !ok { - return nil, nil, false, fmt.Errorf("not a OAuthAuthorizeToken") - } - return labels.Set(obj.Labels), SelectableFields(obj), obj.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) kstorage.SelectionPredicate { - return kstorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *oauthapi.OAuthAuthorizeToken) fields.Set { - return oauthapi.OAuthAuthorizeTokenToSelectableFields(obj) -} diff --git a/pkg/oauth/registry/oauthclientauthorization/etcd/etcd.go b/pkg/oauth/registry/oauthclientauthorization/etcd/etcd.go index 631c8d998fe2..060221935510 100644 --- a/pkg/oauth/registry/oauthclientauthorization/etcd/etcd.go +++ b/pkg/oauth/registry/oauthclientauthorization/etcd/etcd.go @@ -5,6 +5,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" oauthapi "github.com/openshift/origin/pkg/oauth/apis/oauth" @@ -28,7 +29,6 @@ func NewREST(optsGetter restoptions.Getter, clientGetter oauthclient.Getter) (*R Copier: kapi.Scheme, NewFunc: func() runtime.Object { return &oauthapi.OAuthClientAuthorization{} }, NewListFunc: func() runtime.Object { return &oauthapi.OAuthClientAuthorizationList{} }, - PredicateFunc: oauthclientauthorization.Matcher, DefaultQualifiedResource: oauthapi.Resource("oauthclientauthorizations"), CreateStrategy: strategy, @@ -36,7 +36,10 @@ func NewREST(optsGetter restoptions.Getter, clientGetter oauthclient.Getter) (*R DeleteStrategy: strategy, } - options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: oauthclientauthorization.GetAttrs} + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: storage.AttrFunc(storage.DefaultNamespaceScopedAttr).WithFieldMutation(oauthapi.OAuthClientAuthorizationFieldSelector), + } if err := store.CompleteWithOptions(options); err != nil { return nil, err } diff --git a/pkg/oauth/registry/oauthclientauthorization/strategy.go b/pkg/oauth/registry/oauthclientauthorization/strategy.go index 2d5931e799b1..ebc17ffaa347 100644 --- a/pkg/oauth/registry/oauthclientauthorization/strategy.go +++ b/pkg/oauth/registry/oauthclientauthorization/strategy.go @@ -4,14 +4,11 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" apirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - kstorage "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" scopeauthorizer "github.com/openshift/origin/pkg/authorization/authorizer/scope" @@ -115,29 +112,6 @@ func (strategy) AllowUnconditionalUpdate() bool { return false } -// GetAttrs returns labels and fields of a given object for filtering purposes -func GetAttrs(o runtime.Object) (labels.Set, fields.Set, bool, error) { - obj, ok := o.(*oauthapi.OAuthClientAuthorization) - if !ok { - return nil, nil, false, fmt.Errorf("not a OAuthClientAuthorization") - } - return labels.Set(obj.Labels), SelectableFields(obj), obj.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) kstorage.SelectionPredicate { - return kstorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *oauthapi.OAuthClientAuthorization) fields.Set { - return oauthapi.OAuthClientAuthorizationToSelectableFields(obj) -} - // ClientAuthorizationName creates the computed name for a given username, clientName tuple // This cannot change or client authorizations will be have unpredictably func ClientAuthorizationName(userName, clientName string) string { diff --git a/pkg/project/apis/project/v1/conversion.go b/pkg/project/apis/project/v1/conversion.go index c75e294780c9..000de0246867 100644 --- a/pkg/project/apis/project/v1/conversion.go +++ b/pkg/project/apis/project/v1/conversion.go @@ -3,12 +3,45 @@ package v1 import ( "github.com/openshift/origin/pkg/api/apihelpers" "k8s.io/apimachinery/pkg/runtime" - kapi "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/registry/core/namespace" ) func addConversionFuncs(scheme *runtime.Scheme) error { - return scheme.AddFieldLabelConversionFunc("v1", "Project", - apihelpers.GetFieldLabelConversionFunc(namespace.NamespaceToSelectableFields(&kapi.Namespace{}), nil), - ) + return nil +} + +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "Project", legacyProjectFieldSelectorKeyConversionFunc); err != nil { + return err + } + return nil +} + +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Project", projectFieldSelectorKeyConversionFunc); err != nil { + return err + } + return nil +} + +// because field selectors can vary in support by version they are exposed under, we have one function for each +// groupVersion we're registering for +// we don't actually do any evaluation, only passing through, so we don't have our own field selector to test. The upstream +// cannot remove the field selectors or they break compatibility, so we're fine. + +func legacyProjectFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "status.phase": + return label, value, nil + default: + return apihelpers.LegacyMetaV1FieldSelectorConversionWithName(label, value) + } +} + +func projectFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "status.phase": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } } diff --git a/pkg/project/apis/project/v1/conversion_test.go b/pkg/project/apis/project/v1/conversion_test.go deleted file mode 100644 index 5ca479d71e26..000000000000 --- a/pkg/project/apis/project/v1/conversion_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package v1 - -import ( - "testing" - - "github.com/openshift/origin/pkg/api/apihelpers/apitesting" - - "k8s.io/apimachinery/pkg/runtime" - kapi "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/registry/core/namespace" -) - -func TestFieldSelectorConversions(t *testing.T) { - converter := runtime.NewScheme() - LegacySchemeBuilder.AddToScheme(converter) - - apitesting.TestFieldLabelConversions(t, converter, "v1", "Project", - // Ensure all currently returned labels are supported - namespace.NamespaceToSelectableFields(&kapi.Namespace{}), - // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "status.phase", - ) -} diff --git a/pkg/project/apis/project/v1/register.go b/pkg/project/apis/project/v1/register.go index 7e3a938dea31..b89fe3a94f5a 100644 --- a/pkg/project/apis/project/v1/register.go +++ b/pkg/project/apis/project/v1/register.go @@ -16,10 +16,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, addLegacyFieldSelectorKeyConversions) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addFieldSelectorKeyConversions) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/route/apis/route/v1/conversion.go b/pkg/route/apis/route/v1/conversion.go index 7fabaabab440..854d599f77c6 100644 --- a/pkg/route/apis/route/v1/conversion.go +++ b/pkg/route/apis/route/v1/conversion.go @@ -4,15 +4,15 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -func addLegacyFieldConversionFuncs(scheme *runtime.Scheme) error { - if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "Route", legacyRouteFieldSelectorConversionFunc); err != nil { +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "Route", legacyRouteFieldSelectorKeyConversionFunc); err != nil { return err } return nil } -func addFieldConversionFuncs(scheme *runtime.Scheme) error { - if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Route", routeFieldSelectorConversionFunc); err != nil { +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Route", routeFieldSelectorKeyConversionFunc); err != nil { return err } return nil @@ -21,7 +21,7 @@ func addFieldConversionFuncs(scheme *runtime.Scheme) error { // because field selectors can vary in support by version they are exposed under, we have one function for each // groupVersion we're registering for -func legacyRouteFieldSelectorConversionFunc(label, value string) (internalLabel, internalValue string, err error) { +func legacyRouteFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { switch label { case "spec.path", "spec.host", @@ -32,7 +32,7 @@ func legacyRouteFieldSelectorConversionFunc(label, value string) (internalLabel, } } -func routeFieldSelectorConversionFunc(label, value string) (internalLabel, internalValue string, err error) { +func routeFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { switch label { case "spec.path", "spec.host", diff --git a/pkg/route/apis/route/v1/register.go b/pkg/route/apis/route/v1/register.go index 27830aac65d7..07ef65ef9ad1 100644 --- a/pkg/route/apis/route/v1/register.go +++ b/pkg/route/apis/route/v1/register.go @@ -16,10 +16,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addLegacyFieldConversionFuncs, RegisterDefaults) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addLegacyFieldSelectorKeyConversions, RegisterDefaults) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addFieldConversionFuncs, RegisterDefaults) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addFieldSelectorKeyConversions, RegisterDefaults) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/user/apis/user/fields.go b/pkg/user/apis/user/fields.go index 29ee38c5d8a6..6f948e801e99 100644 --- a/pkg/user/apis/user/fields.go +++ b/pkg/user/apis/user/fields.go @@ -1,15 +1,20 @@ package user -import "k8s.io/apimachinery/pkg/fields" +import ( + "fmt" -// IdentityToSelectableFields returns a label set that represents the object -// changes to the returned keys require registering conversions for existing versions using Scheme.AddFieldLabelConversionFunc -func IdentityToSelectableFields(identity *Identity) fields.Set { - return fields.Set{ - "metadata.name": identity.Name, - "providerName": identity.ProviderName, - "providerUserName": identity.ProviderName, - "user.name": identity.User.Name, - "user.uid": string(identity.User.UID), + "k8s.io/apimachinery/pkg/fields" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func IdentityFieldSelector(obj runtime.Object, fieldSet fields.Set) error { + identity, ok := obj.(*Identity) + if !ok { + return fmt.Errorf("%T not an Identity", obj) } + fieldSet["providerName"] = identity.ProviderName + fieldSet["providerUserName"] = identity.ProviderUserName + fieldSet["user.name"] = identity.User.Name + fieldSet["user.uid"] = string(identity.User.UID) + return nil } diff --git a/pkg/user/apis/user/v1/conversion.go b/pkg/user/apis/user/v1/conversion.go index 0306dc55dc03..462a450eb25e 100644 --- a/pkg/user/apis/user/v1/conversion.go +++ b/pkg/user/apis/user/v1/conversion.go @@ -2,17 +2,49 @@ package v1 import ( "k8s.io/apimachinery/pkg/runtime" - - "github.com/openshift/origin/pkg/api/apihelpers" - userapi "github.com/openshift/origin/pkg/user/apis/user" ) func addConversionFuncs(scheme *runtime.Scheme) error { - if err := scheme.AddFieldLabelConversionFunc("v1", "Identity", - apihelpers.GetFieldLabelConversionFunc(userapi.IdentityToSelectableFields(&userapi.Identity{}), nil), - ); err != nil { + return nil +} + +func addLegacyFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(LegacySchemeGroupVersion.String(), "Identity", legacyIdentityFieldSelectorKeyConversionFunc); err != nil { return err } + return nil +} +func addFieldSelectorKeyConversions(scheme *runtime.Scheme) error { + if err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Identity", identityFieldSelectorKeyConversionFunc); err != nil { + return err + } return nil } + +// because field selectors can vary in support by version they are exposed under, we have one function for each +// groupVersion we're registering for + +func legacyIdentityFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "providerName", + "providerUserName", + "user.name", + "user.uid": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} + +func identityFieldSelectorKeyConversionFunc(label, value string) (internalLabel, internalValue string, err error) { + switch label { + case "providerName", + "providerUserName", + "user.name", + "user.uid": + return label, value, nil + default: + return runtime.DefaultMetaV1FieldSelectorConversion(label, value) + } +} diff --git a/pkg/user/apis/user/v1/conversion_test.go b/pkg/user/apis/user/v1/conversion_test.go index f3a1e6ee92a7..58ee0b30e971 100644 --- a/pkg/user/apis/user/v1/conversion_test.go +++ b/pkg/user/apis/user/v1/conversion_test.go @@ -10,13 +10,19 @@ import ( ) func TestFieldSelectorConversions(t *testing.T) { - converter := runtime.NewScheme() - LegacySchemeBuilder.AddToScheme(converter) + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{LegacySchemeBuilder.AddToScheme, userapi.LegacySchemeBuilder.AddToScheme}, + Kind: LegacySchemeGroupVersion.WithKind("Identity"), + // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST + AllowedExternalFieldKeys: []string{"providerName", "providerUserName", "user.name", "user.uid"}, + FieldKeyEvaluatorFn: userapi.IdentityFieldSelector, + }.Check(t) - apitesting.TestFieldLabelConversions(t, converter, "v1", "Identity", - // Ensure all currently returned labels are supported - userapi.IdentityToSelectableFields(&userapi.Identity{}), + apitesting.FieldKeyCheck{ + SchemeBuilder: []func(*runtime.Scheme) error{SchemeBuilder.AddToScheme, userapi.SchemeBuilder.AddToScheme}, + Kind: SchemeGroupVersion.WithKind("Identity"), // Ensure previously supported labels have conversions. DO NOT REMOVE THINGS FROM THIS LIST - "providerName", "providerUserName", "user.name", "user.uid", - ) + AllowedExternalFieldKeys: []string{"providerName", "providerUserName", "user.name", "user.uid"}, + FieldKeyEvaluatorFn: userapi.IdentityFieldSelector, + }.Check(t) } diff --git a/pkg/user/apis/user/v1/register.go b/pkg/user/apis/user/v1/register.go index 3ef714b930fc..5f3bdda9fc85 100644 --- a/pkg/user/apis/user/v1/register.go +++ b/pkg/user/apis/user/v1/register.go @@ -16,10 +16,10 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: "v1"} - LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs) + LegacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, addConversionFuncs, addLegacyFieldSelectorKeyConversions) AddToSchemeInCoreGroup = LegacySchemeBuilder.AddToScheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addFieldSelectorKeyConversions) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/user/registry/identity/etcd/etcd.go b/pkg/user/registry/identity/etcd/etcd.go index 1a6c08f4d089..bfeb1d54eac1 100644 --- a/pkg/user/registry/identity/etcd/etcd.go +++ b/pkg/user/registry/identity/etcd/etcd.go @@ -5,6 +5,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" userapi "github.com/openshift/origin/pkg/user/apis/user" @@ -25,7 +26,6 @@ func NewREST(optsGetter restoptions.Getter) (*REST, error) { Copier: kapi.Scheme, NewFunc: func() runtime.Object { return &userapi.Identity{} }, NewListFunc: func() runtime.Object { return &userapi.IdentityList{} }, - PredicateFunc: identity.Matcher, DefaultQualifiedResource: userapi.Resource("identities"), CreateStrategy: identity.Strategy, @@ -33,7 +33,10 @@ func NewREST(optsGetter restoptions.Getter) (*REST, error) { DeleteStrategy: identity.Strategy, } - options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: identity.GetAttrs} + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: storage.AttrFunc(storage.DefaultNamespaceScopedAttr).WithFieldMutation(userapi.IdentityFieldSelector), + } if err := store.CompleteWithOptions(options); err != nil { return nil, err } diff --git a/pkg/user/registry/identity/strategy.go b/pkg/user/registry/identity/strategy.go index 2e3fb2a9c271..6cbe74d79614 100644 --- a/pkg/user/registry/identity/strategy.go +++ b/pkg/user/registry/identity/strategy.go @@ -1,15 +1,10 @@ package identity import ( - "fmt" - - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" apirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - kstorage "k8s.io/apiserver/pkg/storage" kapi "k8s.io/kubernetes/pkg/api" userapi "github.com/openshift/origin/pkg/user/apis/user" @@ -74,26 +69,3 @@ func (identityStrategy) Canonicalize(obj runtime.Object) { func (identityStrategy) ValidateUpdate(ctx apirequest.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateIdentityUpdate(obj.(*userapi.Identity), old.(*userapi.Identity)) } - -// GetAttrs returns labels and fields of a given object for filtering purposes -func GetAttrs(o runtime.Object) (labels.Set, fields.Set, bool, error) { - obj, ok := o.(*userapi.Identity) - if !ok { - return nil, nil, false, fmt.Errorf("not an Identity") - } - return labels.Set(obj.Labels), SelectableFields(obj), obj.Initializers != nil, nil -} - -// Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) kstorage.SelectionPredicate { - return kstorage.SelectionPredicate{ - Label: label, - Field: field, - GetAttrs: GetAttrs, - } -} - -// SelectableFields returns a field set that can be used for filter selection -func SelectableFields(obj *userapi.Identity) fields.Set { - return userapi.IdentityToSelectableFields(obj) -}