Merge pull request #116062 from liggitt/revert-field-manager

Revert "Merge pull request #115324 from alexzielenski/apiserver/smd/use-openapiv3
This commit is contained in:
Kubernetes Prow Robot 2023-02-25 15:38:17 -08:00 committed by GitHub
commit b670d1ba7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 374 additions and 701 deletions

View File

@ -76,7 +76,6 @@ import (
"k8s.io/client-go/scale/scheme/autoscalingv1"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
"k8s.io/kube-openapi/pkg/validation/strfmt"
"k8s.io/kube-openapi/pkg/validation/validate"
@ -121,7 +120,7 @@ type crdHandler struct {
// staticOpenAPISpec is used as a base for the schema of CR's for the
// purpose of managing fields, it is how CR handlers get the structure
// of TypeMeta and ObjectMeta
staticOpenAPISpec map[string]*spec.Schema
staticOpenAPISpec *spec.Swagger
// The limit on the request size that would be accepted and decoded in a write request
// 0 means no limit.
@ -175,7 +174,7 @@ func NewCustomResourceDefinitionHandler(
authorizer authorizer.Authorizer,
requestTimeout time.Duration,
minRequestTimeout time.Duration,
staticOpenAPISpec map[string]*spec.Schema,
staticOpenAPISpec *spec.Swagger,
maxRequestBodyBytes int64) (*crdHandler, error) {
if converterFactory == nil {
@ -681,7 +680,7 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
}
var typeConverter fieldmanager.TypeConverter = fieldmanager.NewDeducedTypeConverter()
if len(openAPIModels) > 0 {
if openAPIModels != nil {
typeConverter, err = fieldmanager.NewTypeConverter(openAPIModels, crd.Spec.PreserveUnknownFields)
if err != nil {
return nil, err
@ -1370,39 +1369,25 @@ func hasServedCRDVersion(spec *apiextensionsv1.CustomResourceDefinitionSpec, ver
// buildOpenAPIModelsForApply constructs openapi models from any validation schemas specified in the custom resource,
// and merges it with the models defined in the static OpenAPI spec.
// Returns nil models ifthe static spec is nil, or an error is encountered.
func buildOpenAPIModelsForApply(staticOpenAPISpec map[string]*spec.Schema, crd *apiextensionsv1.CustomResourceDefinition) (map[string]*spec.Schema, error) {
func buildOpenAPIModelsForApply(staticOpenAPISpec *spec.Swagger, crd *apiextensionsv1.CustomResourceDefinition) (*spec.Swagger, error) {
if staticOpenAPISpec == nil {
return nil, nil
}
// Convert static spec to V3 format to be able to merge
staticSpecV3 := &spec3.OpenAPI{
Version: "3.0.0",
Info: &spec.Info{
InfoProps: spec.InfoProps{
Title: "Kubernetes CRD Swagger",
Version: "v0.1.0",
},
},
Components: &spec3.Components{
Schemas: staticOpenAPISpec,
},
}
specs := []*spec3.OpenAPI{staticSpecV3}
specs := []*spec.Swagger{}
for _, v := range crd.Spec.Versions {
// Defaults are not pruned here, but before being served.
// See flag description in builder.go for flag usage
s, err := builder.BuildOpenAPIV3(crd, v.Name, builder.Options{})
s, err := builder.BuildOpenAPIV2(crd, v.Name, builder.Options{V2: true, SkipFilterSchemaForKubectlOpenAPIV2Validation: true, StripValueValidation: true, StripNullable: true, AllowNonStructural: false})
if err != nil {
return nil, err
}
specs = append(specs, s)
}
mergedOpenAPI, err := builder.MergeSpecsV3(specs...)
mergedOpenAPI, err := builder.MergeSpecs(staticOpenAPISpec, specs...)
if err != nil {
return nil, err
}
return mergedOpenAPI.Components.Schemas, nil
return mergedOpenAPI, nil
}

View File

@ -1023,15 +1023,9 @@ func TestBuildOpenAPIModelsForApply(t *testing.T) {
},
}
convertedDefs := map[string]*spec.Schema{}
for k, v := range staticSpec.Definitions {
vCopy := v
convertedDefs[k] = &vCopy
}
for i, test := range tests {
crd.Spec.Versions[0].Schema = &test
models, err := buildOpenAPIModelsForApply(convertedDefs, &crd)
models, err := buildOpenAPIModelsForApply(staticSpec, &crd)
if err != nil {
t.Fatalf("failed to convert to apply model: %v", err)
}

View File

@ -34,6 +34,7 @@ import (
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/storageversion"
"k8s.io/kube-openapi/pkg/validation/spec"
)
// ConvertabilityChecker indicates what versions a GroupKind is available in.
@ -94,6 +95,9 @@ type APIGroupVersion struct {
MinRequestTimeout time.Duration
// OpenAPIModels exposes the OpenAPI models to each individual handler.
OpenAPIModels *spec.Swagger
// The limit on the request body size that would be accepted and decoded in a write request.
// 0 means no limit.
MaxRequestBodyBytes int64

View File

@ -47,16 +47,11 @@ var fakeTypeConverter = func() fieldmanager.TypeConverter {
if err != nil {
panic(err)
}
swag := spec.Swagger{}
if err := json.Unmarshal(data, &swag); err != nil {
spec := spec.Swagger{}
if err := json.Unmarshal(data, &spec); err != nil {
panic(err)
}
convertedDefs := map[string]*spec.Schema{}
for k, v := range swag.Definitions {
vCopy := v
convertedDefs[k] = &vCopy
}
typeConverter, err := fieldmanager.NewTypeConverter(convertedDefs, false)
typeConverter, err := fieldmanager.NewTypeConverter(&spec, false)
if err != nil {
panic(err)
}

View File

@ -33,18 +33,11 @@ var fakeTypeConverter = func() internal.TypeConverter {
if err != nil {
panic(err)
}
convertedDefs := map[string]*spec.Schema{}
spec := spec.Swagger{}
if err := json.Unmarshal(data, &spec); err != nil {
panic(err)
}
for k, v := range spec.Definitions {
vCopy := v
convertedDefs[k] = &vCopy
}
typeConverter, err := internal.NewTypeConverter(convertedDefs, false)
typeConverter, err := internal.NewTypeConverter(&spec, false)
if err != nil {
panic(err)
}

View File

@ -42,14 +42,23 @@ type typeConverter struct {
var _ TypeConverter = &typeConverter{}
func NewTypeConverter(openapiSpec map[string]*spec.Schema, preserveUnknownFields bool) (TypeConverter, error) {
typeSchema, err := schemaconv.ToSchemaFromOpenAPI(openapiSpec, preserveUnknownFields)
// NewTypeConverter builds a TypeConverter from a spec.Swagger. This
// will automatically find the proper version of the object, and the
// corresponding schema information.
func NewTypeConverter(openapiSpec *spec.Swagger, preserveUnknownFields bool) (TypeConverter, error) {
pointerDefs := map[string]*spec.Schema{}
for k, v := range openapiSpec.Definitions {
vCopy := v
pointerDefs[k] = &vCopy
}
typeSchema, err := schemaconv.ToSchemaFromOpenAPI(pointerDefs, preserveUnknownFields)
if err != nil {
return nil, fmt.Errorf("failed to convert models to schema: %v", err)
}
typeParser := typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}}
tr := indexModels(&typeParser, openapiSpec)
tr := indexModels(&typeParser, pointerDefs)
return &typeConverter{parser: tr}, nil
}

View File

@ -36,17 +36,11 @@ var testTypeConverter = func() TypeConverter {
if err != nil {
panic(err)
}
swag := spec.Swagger{}
if err := json.Unmarshal(data, &swag); err != nil {
spec := spec.Swagger{}
if err := json.Unmarshal(data, &spec); err != nil {
panic(err)
}
convertedDefs := map[string]*spec.Schema{}
for k, v := range swag.Definitions {
vCopy := v
convertedDefs[k] = &vCopy
}
typeConverter, err := NewTypeConverter(convertedDefs, false)
typeConverter, err := NewTypeConverter(&spec, false)
if err != nil {
panic(err)
}

View File

@ -34,14 +34,9 @@ func NewDeducedTypeConverter() TypeConverter {
return internal.NewDeducedTypeConverter()
}
// NewTypeConverter builds a TypeConverter from a map of OpenAPIV3 schemas.
// This will automatically find the proper version of the object, and the
// NewTypeConverter builds a TypeConverter from a proto.Models. This
// will automatically find the proper version of the object, and the
// corresponding schema information.
// The keys to the map must be consistent with the names
// used by Refs within the schemas.
// The schemas should conform to the Kubernetes Structural Schema OpenAPI
// restrictions found in docs:
// https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema
func NewTypeConverter(openapiSpec map[string]*spec.Schema, preserveUnknownFields bool) (TypeConverter, error) {
func NewTypeConverter(openapiSpec *spec.Swagger, preserveUnknownFields bool) (TypeConverter, error) {
return internal.NewTypeConverter(openapiSpec, preserveUnknownFields)
}

View File

@ -345,6 +345,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
isCreater = true
}
var resetFields map[fieldpath.APIVersion]*fieldpath.Set
if a.group.OpenAPIModels != nil {
if resetFieldsStrategy, isResetFieldsStrategy := storage.(rest.ResetFieldsStrategy); isResetFieldsStrategy {
resetFields = resetFieldsStrategy.GetResetFields()
}
}
var versionedList interface{}
if isLister {
list := lister.NewList()
@ -673,16 +680,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if a.group.MetaGroupVersion != nil {
reqScope.MetaGroupVersion = *a.group.MetaGroupVersion
}
// Use TypeConverter's nil-ness as a proxy for whether SSA/OpenAPI is enabled
// This should be removed in the future and made unconditional
// https://github.com/kubernetes/kubernetes/pull/114998
if a.group.TypeConverter != nil {
var resetFields map[fieldpath.APIVersion]*fieldpath.Set
if resetFieldsStrategy, isResetFieldsStrategy := storage.(rest.ResetFieldsStrategy); isResetFieldsStrategy {
resetFields = resetFieldsStrategy.GetResetFields()
}
if a.group.OpenAPIModels != nil {
reqScope.FieldManager, err = fieldmanager.NewDefaultFieldManager(
a.group.TypeConverter,
a.group.UnsafeConvertor,
@ -697,7 +695,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
return nil, nil, fmt.Errorf("failed to create field manager: %v", err)
}
}
for _, action := range actions {
producedObject := storageMeta.ProducesObject(action.Verb)
if producedObject == nil {

View File

@ -51,7 +51,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
openapibuilder3 "k8s.io/kube-openapi/pkg/builder3"
openapibuilder2 "k8s.io/kube-openapi/pkg/builder"
openapicommon "k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/handler"
"k8s.io/kube-openapi/pkg/handler3"
@ -87,7 +87,7 @@ type APIGroupInfo struct {
// StaticOpenAPISpec is the spec derived from the definitions of all resources installed together.
// It is set during InstallAPIGroups, InstallAPIGroup, and InstallLegacyAPIGroup.
StaticOpenAPISpec map[string]*spec.Schema
StaticOpenAPISpec *spec.Swagger
}
func (a *APIGroupInfo) destroyStorage() {
@ -666,16 +666,7 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}, shutdow
}
// installAPIResources is a private method for installing the REST storage backing each api groupversionresource
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo, openAPIModels map[string]*spec.Schema) error {
var typeConverter fieldmanager.TypeConverter
if len(openAPIModels) > 0 {
var err error
typeConverter, err = fieldmanager.NewTypeConverter(openAPIModels, false)
if err != nil {
return err
}
}
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo, openAPIModels *spec.Swagger) error {
var resourceInfos []*storageversion.ResourceInfo
for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
@ -690,7 +681,16 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
if apiGroupInfo.OptionsExternalVersion != nil {
apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
}
apiGroupVersion.TypeConverter = typeConverter
apiGroupVersion.OpenAPIModels = openAPIModels
if openAPIModels != nil {
typeConverter, err := fieldmanager.NewTypeConverter(openAPIModels, false)
if err != nil {
return err
}
apiGroupVersion.TypeConverter = typeConverter
}
apiGroupVersion.MaxRequestBodyBytes = s.maxRequestBodyBytes
discoveryAPIResources, r, err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer)
@ -881,10 +881,8 @@ func NewDefaultAPIGroupInfo(group string, scheme *runtime.Scheme, parameterCodec
}
// getOpenAPIModels is a private method for getting the OpenAPI models
func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*APIGroupInfo) (map[string]*spec.Schema, error) {
if s.openAPIV3Config == nil {
//!TODO: A future work should add a requirement that
// OpenAPIV3 config is required. May require some refactoring of tests.
func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*APIGroupInfo) (*spec.Swagger, error) {
if s.openAPIConfig == nil {
return nil, nil
}
pathsToIgnore := openapiutil.NewTrie(s.openAPIConfig.IgnorePrefixes)
@ -898,7 +896,7 @@ func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*
}
// Build the openapi definitions for those resources and convert it to proto models
openAPISpec, err := openapibuilder3.BuildOpenAPIDefinitionsForResources(s.openAPIV3Config, resourceNames...)
openAPISpec, err := openapibuilder2.BuildOpenAPIDefinitionsForResources(s.openAPIConfig, resourceNames...)
if err != nil {
return nil, err
}