OpenAPIResourcesGetter allows lazy-loading OpenAPI V2

Kubernetes-commit: 6614a29f470f802915d1467f5050dbca1f8bc562
This commit is contained in:
Sean Sullivan 2023-03-13 20:28:40 -07:00 committed by Kubernetes Publisher
parent e22d02e126
commit 348bd97228
5 changed files with 34 additions and 18 deletions

View File

@ -62,8 +62,10 @@ type Factory interface {
// Returns a schema that can validate objects stored on disk. // Returns a schema that can validate objects stored on disk.
Validator(validationDirective string) (validation.Schema, error) Validator(validationDirective string) (validation.Schema, error)
// OpenAPISchema returns the parsed openapi schema definition
OpenAPISchema() (openapi.Resources, error) // Used for retrieving openapi v2 resources.
openapi.OpenAPIResourcesGetter
// OpenAPIV3Schema returns a client for fetching parsed schemas for // OpenAPIV3Schema returns a client for fetching parsed schemas for
// any group version // any group version
OpenAPIV3Client() (openapiclient.Client, error) OpenAPIV3Client() (openapiclient.Client, error)

View File

@ -154,13 +154,8 @@ func (f *factoryImpl) Validator(validationDirective string) (validation.Schema,
return validation.NullSchema{}, nil return validation.NullSchema{}, nil
} }
resources, err := f.OpenAPISchema()
if err != nil {
return nil, err
}
schema := validation.ConjunctiveSchema{ schema := validation.ConjunctiveSchema{
validation.NewSchemaValidation(resources), validation.NewSchemaValidation(f),
validation.NoDoubleKeySchema{}, validation.NoDoubleKeySchema{},
} }

View File

@ -24,6 +24,13 @@ import (
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
// OpenAPIResourcesGetter represents a function to return
// OpenAPI V2 resource specifications. Used for lazy-loading
// these resource specifications.
type OpenAPIResourcesGetter interface {
OpenAPISchema() (Resources, error)
}
// Resources interface describe a resources provider, that can give you // Resources interface describe a resources provider, that can give you
// resource based on group-version-kind. // resource based on group-version-kind.
type Resources interface { type Resources interface {

View File

@ -29,14 +29,14 @@ import (
// schemaValidation validates the object against an OpenAPI schema. // schemaValidation validates the object against an OpenAPI schema.
type schemaValidation struct { type schemaValidation struct {
resources openapi.Resources resourcesGetter openapi.OpenAPIResourcesGetter
} }
// NewSchemaValidation creates a new Schema that can be used // NewSchemaValidation creates a new Schema that can be used
// to validate objects. // to validate objects.
func NewSchemaValidation(resources openapi.Resources) Schema { func NewSchemaValidation(resourcesGetter openapi.OpenAPIResourcesGetter) Schema {
return &schemaValidation{ return &schemaValidation{
resources: resources, resourcesGetter: resourcesGetter,
} }
} }
@ -56,7 +56,6 @@ func (v *schemaValidation) ValidateBytes(data []byte) error {
if (gvk == schema.GroupVersionKind{Version: "v1", Kind: "List"}) { if (gvk == schema.GroupVersionKind{Version: "v1", Kind: "List"}) {
return utilerrors.NewAggregate(v.validateList(obj)) return utilerrors.NewAggregate(v.validateList(obj))
} }
return utilerrors.NewAggregate(v.validateResource(obj, gvk)) return utilerrors.NewAggregate(v.validateResource(obj, gvk))
} }
@ -81,7 +80,12 @@ func (v *schemaValidation) validateList(object interface{}) []error {
} }
func (v *schemaValidation) validateResource(obj interface{}, gvk schema.GroupVersionKind) []error { func (v *schemaValidation) validateResource(obj interface{}, gvk schema.GroupVersionKind) []error {
resource := v.resources.LookupResource(gvk) // This lazy-loads the OpenAPI V2 specifications, caching the specs.
resources, err := v.resourcesGetter.OpenAPISchema()
if err != nil {
return []error{err}
}
resource := resources.LookupResource(gvk)
if resource == nil { if resource == nil {
// resource is not present, let's just skip validation. // resource is not present, let's just skip validation.
return nil return nil

View File

@ -32,14 +32,22 @@ import (
var fakeSchema = testing.Fake{Path: filepath.Join("..", "..", "testdata", "openapi", "swagger.json")} var fakeSchema = testing.Fake{Path: filepath.Join("..", "..", "testdata", "openapi", "swagger.json")}
// fakeResourcesGetter implements the OpenAPIResourcesGetter interface, returning the
// openapi resources from the swagger.json (above).
type fakeResourcesGetter struct{}
func (r *fakeResourcesGetter) OpenAPISchema() (openapi.Resources, error) {
doc, err := fakeSchema.OpenAPISchema()
if err != nil {
return nil, err
}
return openapi.NewOpenAPIData(doc)
}
var _ = Describe("resource validation using OpenAPI Schema", func() { var _ = Describe("resource validation using OpenAPI Schema", func() {
var validator Schema var validator Schema
BeforeEach(func() { BeforeEach(func() {
s, err := fakeSchema.OpenAPISchema() validator = NewSchemaValidation(&fakeResourcesGetter{})
Expect(err).ToNot(HaveOccurred())
resources, err := openapi.NewOpenAPIData(s)
Expect(err).ToNot(HaveOccurred())
validator = NewSchemaValidation(resources)
Expect(validator).ToNot(BeNil()) Expect(validator).ToNot(BeNil())
}) })