Merge pull request #114792 from apelisse/typeconverter-swagger

Hide OpenAPI details behind the NewTypeConverter
This commit is contained in:
Kubernetes Prow Robot 2023-01-04 14:30:21 -08:00 committed by GitHub
commit 92b113c48d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 79 deletions

View File

@ -71,13 +71,11 @@ import (
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic"
genericfilters "k8s.io/apiserver/pkg/server/filters"
utilopenapi "k8s.io/apiserver/pkg/util/openapi"
"k8s.io/apiserver/pkg/warning"
"k8s.io/client-go/scale"
"k8s.io/client-go/scale/scheme/autoscalingv1"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
"k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/validation/spec"
"k8s.io/kube-openapi/pkg/validation/strfmt"
"k8s.io/kube-openapi/pkg/validation/validate"
@ -1371,7 +1369,7 @@ 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 *spec.Swagger, crd *apiextensionsv1.CustomResourceDefinition) (proto.Models, error) {
func buildOpenAPIModelsForApply(staticOpenAPISpec *spec.Swagger, crd *apiextensionsv1.CustomResourceDefinition) (*spec.Swagger, error) {
if staticOpenAPISpec == nil {
return nil, nil
}
@ -1391,9 +1389,5 @@ func buildOpenAPIModelsForApply(staticOpenAPISpec *spec.Swagger, crd *apiextensi
if err != nil {
return nil, err
}
models, err := utilopenapi.ToProtoModels(mergedOpenAPI)
if err != nil {
return nil, err
}
return models, nil
return mergedOpenAPI, nil
}

View File

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

View File

@ -17,8 +17,10 @@ limitations under the License.
package fieldmanagertest
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
@ -28,39 +30,34 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
"k8s.io/kube-openapi/pkg/util/proto"
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
"k8s.io/kube-openapi/pkg/validation/spec"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
"sigs.k8s.io/structured-merge-diff/v4/merge"
"sigs.k8s.io/structured-merge-diff/v4/typed"
)
var kubernetesSwaggerSchema = prototesting.Fake{
Path: filepath.Join(
var builtinConverter = func() fieldmanager.TypeConverter {
data, err := ioutil.ReadFile(filepath.Join(
strings.Repeat(".."+string(filepath.Separator), 8),
"api", "openapi-spec", "swagger.json"),
}
// NewBuiltinTypeConverter creates a TypeConverter with all the built-in
// types defined, given the committed kubernetes swagger.json.
func NewBuiltinTypeConverter() fieldmanager.TypeConverter {
tc, err := fieldmanager.NewTypeConverter(newFakeOpenAPIModels(), false)
"api", "openapi-spec", "swagger.json"))
if err != nil {
panic(err)
}
spec := spec.Swagger{}
if err := json.Unmarshal(data, &spec); err != nil {
panic(err)
}
tc, err := fieldmanager.NewTypeConverter(&spec, false)
if err != nil {
panic(fmt.Errorf("Failed to build TypeConverter: %v", err))
}
return tc
}
}()
func newFakeOpenAPIModels() proto.Models {
d, err := kubernetesSwaggerSchema.OpenAPISchema()
if err != nil {
panic(err)
}
m, err := proto.NewOpenAPIData(d)
if err != nil {
panic(err)
}
return m
// NewBuiltinTypeConverter creates a TypeConverter with all the built-in
// types defined, given the committed kubernetes swagger.json.
func NewBuiltinTypeConverter() fieldmanager.TypeConverter {
return builtinConverter
}
type fakeObjectConvertor struct {

View File

@ -23,7 +23,8 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/managedfields"
"k8s.io/kube-openapi/pkg/util/proto"
utilopenapi "k8s.io/apiserver/pkg/util/openapi"
"k8s.io/kube-openapi/pkg/validation/spec"
"sigs.k8s.io/structured-merge-diff/v4/typed"
"sigs.k8s.io/structured-merge-diff/v4/value"
)
@ -70,10 +71,14 @@ type typeConverter struct {
var _ TypeConverter = &typeConverter{}
// NewTypeConverter builds a TypeConverter from a proto.Models. This
// 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(models proto.Models, preserveUnknownFields bool) (TypeConverter, error) {
func NewTypeConverter(openapiSpec *spec.Swagger, preserveUnknownFields bool) (TypeConverter, error) {
models, err := utilopenapi.ToProtoModels(openapiSpec)
if err != nil {
return nil, err
}
parser, err := managedfields.NewGVKParser(models, preserveUnknownFields)
if err != nil {
return nil, err

View File

@ -17,7 +17,9 @@ limitations under the License.
package fieldmanager_test
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"reflect"
"testing"
@ -27,25 +29,23 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
"k8s.io/kube-openapi/pkg/util/proto"
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
"k8s.io/kube-openapi/pkg/validation/spec"
)
var testSchema = prototesting.Fake{
Path: filepath.Join("testdata", "swagger.json"),
}
var testSchema = func() *spec.Swagger {
data, err := ioutil.ReadFile(filepath.Join("testdata", "swagger.json"))
if err != nil {
panic(err)
}
spec := spec.Swagger{}
if err := json.Unmarshal(data, &spec); err != nil {
panic(err)
}
return &spec
}()
func TestTypeConverter(t *testing.T) {
d, err := testSchema.OpenAPISchema()
if err != nil {
t.Fatalf("Failed to parse OpenAPI schema: %v", err)
}
m, err := proto.NewOpenAPIData(d)
if err != nil {
t.Fatalf("Failed to build OpenAPI models: %v", err)
}
tc, err := fieldmanager.NewTypeConverter(m, false)
tc, err := fieldmanager.NewTypeConverter(testSchema, false)
if err != nil {
t.Fatalf("Failed to build TypeConverter: %v", err)
}
@ -177,16 +177,7 @@ spec:
b.Fatalf("Failed to parse yaml object: %v", err)
}
d, err := testSchema.OpenAPISchema()
if err != nil {
b.Fatalf("Failed to parse OpenAPI schema: %v", err)
}
m, err := proto.NewOpenAPIData(d)
if err != nil {
b.Fatalf("Failed to build OpenAPI models: %v", err)
}
tc, err := fieldmanager.NewTypeConverter(m, false)
tc, err := fieldmanager.NewTypeConverter(testSchema, false)
if err != nil {
b.Fatalf("Failed to build TypeConverter: %v", err)
}

View File

@ -17,7 +17,9 @@ limitations under the License.
package fieldmanager
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"reflect"
"testing"
@ -25,26 +27,25 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/util/proto"
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
"k8s.io/kube-openapi/pkg/validation/spec"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
)
var testSchema = prototesting.Fake{
Path: filepath.Join("testdata", "swagger.json"),
}
var testSchema = func() *spec.Swagger {
data, err := ioutil.ReadFile(filepath.Join("testdata", "swagger.json"))
if err != nil {
panic(err)
}
spec := spec.Swagger{}
if err := json.Unmarshal(data, &spec); err != nil {
panic(err)
}
return &spec
}()
// TestVersionConverter tests the version converter
func TestVersionConverter(t *testing.T) {
d, err := testSchema.OpenAPISchema()
if err != nil {
t.Fatalf("Failed to parse OpenAPI schema: %v", err)
}
m, err := proto.NewOpenAPIData(d)
if err != nil {
t.Fatalf("Failed to build OpenAPI models: %v", err)
}
tc, err := NewTypeConverter(m, false)
tc, err := NewTypeConverter(testSchema, false)
if err != nil {
t.Fatalf("Failed to build TypeConverter: %v", err)
}

View File

@ -49,7 +49,6 @@ import (
"k8s.io/apiserver/pkg/server/routes"
"k8s.io/apiserver/pkg/storageversion"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilopenapi "k8s.io/apiserver/pkg/util/openapi"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
openapibuilder2 "k8s.io/kube-openapi/pkg/builder"
@ -57,7 +56,6 @@ import (
"k8s.io/kube-openapi/pkg/handler"
"k8s.io/kube-openapi/pkg/handler3"
openapiutil "k8s.io/kube-openapi/pkg/util"
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/validation/spec"
"k8s.io/utils/clock"
)
@ -666,7 +664,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 openapiproto.Models) error {
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 {
@ -881,7 +879,7 @@ 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) (openapiproto.Models, error) {
func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*APIGroupInfo) (*spec.Swagger, error) {
if s.openAPIConfig == nil {
return nil, nil
}
@ -903,7 +901,7 @@ func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*
for _, apiGroupInfo := range apiGroupInfos {
apiGroupInfo.StaticOpenAPISpec = openAPISpec
}
return utilopenapi.ToProtoModels(openAPISpec)
return openAPISpec, nil
}
// getResourceNamesForGroup is a private method for getting the canonical names for each resource to build in an api group