diff --git a/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/combined.go b/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/combined.go new file mode 100644 index 00000000000..8a1832097e3 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/combined.go @@ -0,0 +1,45 @@ +/* +Copyright 2023 The Kubernetes Authors. + +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 resolver + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kube-openapi/pkg/validation/spec" +) + +// Combine combines the DefinitionsSchemaResolver with a secondary schema resolver. +// The resulting schema resolver uses the DefinitionsSchemaResolver for a GVK that DefinitionsSchemaResolver knows, +// and the secondary otherwise. +func (d *DefinitionsSchemaResolver) Combine(secondary SchemaResolver) SchemaResolver { + return &combinedSchemaResolver{definitions: d, secondary: secondary} +} + +type combinedSchemaResolver struct { + definitions *DefinitionsSchemaResolver + secondary SchemaResolver +} + +// ResolveSchema takes a GroupVersionKind (GVK) and returns the OpenAPI schema +// identified by the GVK. +// If the DefinitionsSchemaResolver knows the gvk, the DefinitionsSchemaResolver handles the resolution, +// otherwise, the secondary does. +func (r *combinedSchemaResolver) ResolveSchema(gvk schema.GroupVersionKind) (*spec.Schema, error) { + if _, ok := r.definitions.gvkToSchema[gvk]; ok { + return r.definitions.ResolveSchema(gvk) + } + return r.secondary.ResolveSchema(gvk) +} diff --git a/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/definitions.go b/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/definitions.go index df7357f7785..9641a2421e3 100644 --- a/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/definitions.go +++ b/staging/src/k8s.io/apiserver/pkg/cel/openapi/resolver/definitions.go @@ -35,11 +35,11 @@ type DefinitionsSchemaResolver struct { // NewDefinitionsSchemaResolver creates a new DefinitionsSchemaResolver. // An example working setup: -// scheme = "k8s.io/client-go/kubernetes/scheme".Scheme // getDefinitions = "k8s.io/kubernetes/pkg/generated/openapi".GetOpenAPIDefinitions -func NewDefinitionsSchemaResolver(scheme *runtime.Scheme, getDefinitions common.GetOpenAPIDefinitions) *DefinitionsSchemaResolver { +// scheme = "k8s.io/client-go/kubernetes/scheme".Scheme +func NewDefinitionsSchemaResolver(getDefinitions common.GetOpenAPIDefinitions, schemes ...*runtime.Scheme) *DefinitionsSchemaResolver { gvkToSchema := make(map[schema.GroupVersionKind]*spec.Schema) - namer := openapi.NewDefinitionNamer(scheme) + namer := openapi.NewDefinitionNamer(schemes...) defs := getDefinitions(func(path string) spec.Ref { return spec.MustCreateRef(path) }) diff --git a/test/integration/apiserver/cel/typeresolution_test.go b/test/integration/apiserver/cel/typeresolution_test.go index 76d4a42296f..869921c1226 100644 --- a/test/integration/apiserver/cel/typeresolution_test.go +++ b/test/integration/apiserver/cel/typeresolution_test.go @@ -79,7 +79,7 @@ func TestTypeResolver(t *testing.T) { } }(crd) discoveryResolver := &resolver.ClientDiscoveryResolver{Discovery: client.Discovery()} - definitionsResolver := resolver.NewDefinitionsSchemaResolver(k8sscheme.Scheme, openapi.GetOpenAPIDefinitions) + definitionsResolver := resolver.NewDefinitionsSchemaResolver(openapi.GetOpenAPIDefinitions, k8sscheme.Scheme) // wait until the CRD schema is published at the OpenAPI v3 endpoint err = wait.PollImmediate(time.Second, time.Minute, func() (done bool, err error) { p, err := client.OpenAPIV3().Paths() @@ -330,7 +330,7 @@ func TestBuiltinResolution(t *testing.T) { }{ { name: "definitions", - resolver: resolver.NewDefinitionsSchemaResolver(k8sscheme.Scheme, openapi.GetOpenAPIDefinitions), + resolver: resolver.NewDefinitionsSchemaResolver(openapi.GetOpenAPIDefinitions, k8sscheme.Scheme), scheme: buildTestScheme(), }, {