mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Hide OpeAPI details behind the NewTypeConverter
The fact that we're building the OpenAPI using the proto.Models is an implementation detail that we shouldn't have to expose. Since we're going to change the way this is transformed, let's first hide it behind the common NewTypeConverter so that the next change is transparent. This will also enable other clean-ups like hiding the gvkParser which shouldn't be exposed and prevent some refactoring.
This commit is contained in:
parent
88c952d256
commit
a7ab6b86db
@ -71,13 +71,11 @@ import (
|
|||||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
genericfilters "k8s.io/apiserver/pkg/server/filters"
|
genericfilters "k8s.io/apiserver/pkg/server/filters"
|
||||||
utilopenapi "k8s.io/apiserver/pkg/util/openapi"
|
|
||||||
"k8s.io/apiserver/pkg/warning"
|
"k8s.io/apiserver/pkg/warning"
|
||||||
"k8s.io/client-go/scale"
|
"k8s.io/client-go/scale"
|
||||||
"k8s.io/client-go/scale/scheme/autoscalingv1"
|
"k8s.io/client-go/scale/scheme/autoscalingv1"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"k8s.io/kube-openapi/pkg/util/proto"
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
"k8s.io/kube-openapi/pkg/validation/strfmt"
|
"k8s.io/kube-openapi/pkg/validation/strfmt"
|
||||||
"k8s.io/kube-openapi/pkg/validation/validate"
|
"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,
|
// 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.
|
// 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.
|
// 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 {
|
if staticOpenAPISpec == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -1391,9 +1389,5 @@ func buildOpenAPIModelsForApply(staticOpenAPISpec *spec.Swagger, crd *apiextensi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
models, err := utilopenapi.ToProtoModels(mergedOpenAPI)
|
return mergedOpenAPI, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return models, nil
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storageversion"
|
"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.
|
// ConvertabilityChecker indicates what versions a GroupKind is available in.
|
||||||
@ -96,7 +96,7 @@ type APIGroupVersion struct {
|
|||||||
MinRequestTimeout time.Duration
|
MinRequestTimeout time.Duration
|
||||||
|
|
||||||
// OpenAPIModels exposes the OpenAPI models to each individual handler.
|
// 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.
|
// The limit on the request body size that would be accepted and decoded in a write request.
|
||||||
// 0 means no limit.
|
// 0 means no limit.
|
||||||
|
@ -17,8 +17,10 @@ limitations under the License.
|
|||||||
package fieldmanagertest
|
package fieldmanagertest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -28,39 +30,34 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||||
"k8s.io/kube-openapi/pkg/util/proto"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
|
|
||||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
||||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||||
)
|
)
|
||||||
|
|
||||||
var kubernetesSwaggerSchema = prototesting.Fake{
|
var builtinConverter = func() fieldmanager.TypeConverter {
|
||||||
Path: filepath.Join(
|
data, err := ioutil.ReadFile(filepath.Join(
|
||||||
strings.Repeat(".."+string(filepath.Separator), 8),
|
strings.Repeat(".."+string(filepath.Separator), 8),
|
||||||
"api", "openapi-spec", "swagger.json"),
|
"api", "openapi-spec", "swagger.json"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
spec := spec.Swagger{}
|
||||||
// NewBuiltinTypeConverter creates a TypeConverter with all the built-in
|
if err := json.Unmarshal(data, &spec); err != nil {
|
||||||
// types defined, given the committed kubernetes swagger.json.
|
panic(err)
|
||||||
func NewBuiltinTypeConverter() fieldmanager.TypeConverter {
|
}
|
||||||
tc, err := fieldmanager.NewTypeConverter(newFakeOpenAPIModels(), false)
|
tc, err := fieldmanager.NewTypeConverter(&spec, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("Failed to build TypeConverter: %v", err))
|
panic(fmt.Errorf("Failed to build TypeConverter: %v", err))
|
||||||
}
|
}
|
||||||
return tc
|
return tc
|
||||||
}
|
}()
|
||||||
|
|
||||||
func newFakeOpenAPIModels() proto.Models {
|
// NewBuiltinTypeConverter creates a TypeConverter with all the built-in
|
||||||
d, err := kubernetesSwaggerSchema.OpenAPISchema()
|
// types defined, given the committed kubernetes swagger.json.
|
||||||
if err != nil {
|
func NewBuiltinTypeConverter() fieldmanager.TypeConverter {
|
||||||
panic(err)
|
return builtinConverter
|
||||||
}
|
|
||||||
m, err := proto.NewOpenAPIData(d)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeObjectConvertor struct {
|
type fakeObjectConvertor struct {
|
||||||
|
@ -23,7 +23,8 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/managedfields"
|
"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/typed"
|
||||||
"sigs.k8s.io/structured-merge-diff/v4/value"
|
"sigs.k8s.io/structured-merge-diff/v4/value"
|
||||||
)
|
)
|
||||||
@ -70,10 +71,14 @@ type typeConverter struct {
|
|||||||
|
|
||||||
var _ TypeConverter = &typeConverter{}
|
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
|
// will automatically find the proper version of the object, and the
|
||||||
// corresponding schema information.
|
// 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)
|
parser, err := managedfields.NewGVKParser(models, preserveUnknownFields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -17,7 +17,9 @@ limitations under the License.
|
|||||||
package fieldmanager_test
|
package fieldmanager_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -27,25 +29,23 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||||
"k8s.io/kube-openapi/pkg/util/proto"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var testSchema = prototesting.Fake{
|
var testSchema = func() *spec.Swagger {
|
||||||
Path: filepath.Join("testdata", "swagger.json"),
|
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) {
|
func TestTypeConverter(t *testing.T) {
|
||||||
d, err := testSchema.OpenAPISchema()
|
tc, err := fieldmanager.NewTypeConverter(testSchema, false)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to build TypeConverter: %v", err)
|
t.Fatalf("Failed to build TypeConverter: %v", err)
|
||||||
}
|
}
|
||||||
@ -177,16 +177,7 @@ spec:
|
|||||||
b.Fatalf("Failed to parse yaml object: %v", err)
|
b.Fatalf("Failed to parse yaml object: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d, err := testSchema.OpenAPISchema()
|
tc, err := fieldmanager.NewTypeConverter(testSchema, false)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Failed to build TypeConverter: %v", err)
|
b.Fatalf("Failed to build TypeConverter: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@ limitations under the License.
|
|||||||
package fieldmanager
|
package fieldmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -25,26 +27,25 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kube-openapi/pkg/util/proto"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
|
|
||||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testSchema = prototesting.Fake{
|
var testSchema = func() *spec.Swagger {
|
||||||
Path: filepath.Join("testdata", "swagger.json"),
|
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
|
// TestVersionConverter tests the version converter
|
||||||
func TestVersionConverter(t *testing.T) {
|
func TestVersionConverter(t *testing.T) {
|
||||||
d, err := testSchema.OpenAPISchema()
|
tc, err := NewTypeConverter(testSchema, false)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to build TypeConverter: %v", err)
|
t.Fatalf("Failed to build TypeConverter: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/server/routes"
|
"k8s.io/apiserver/pkg/server/routes"
|
||||||
"k8s.io/apiserver/pkg/storageversion"
|
"k8s.io/apiserver/pkg/storageversion"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
utilopenapi "k8s.io/apiserver/pkg/util/openapi"
|
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
openapibuilder2 "k8s.io/kube-openapi/pkg/builder"
|
openapibuilder2 "k8s.io/kube-openapi/pkg/builder"
|
||||||
@ -57,7 +56,6 @@ import (
|
|||||||
"k8s.io/kube-openapi/pkg/handler"
|
"k8s.io/kube-openapi/pkg/handler"
|
||||||
"k8s.io/kube-openapi/pkg/handler3"
|
"k8s.io/kube-openapi/pkg/handler3"
|
||||||
openapiutil "k8s.io/kube-openapi/pkg/util"
|
openapiutil "k8s.io/kube-openapi/pkg/util"
|
||||||
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
"k8s.io/utils/clock"
|
"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
|
// 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
|
var resourceInfos []*storageversion.ResourceInfo
|
||||||
for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
|
for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
|
||||||
if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
|
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
|
// 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 {
|
if s.openAPIConfig == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -903,7 +901,7 @@ func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*
|
|||||||
for _, apiGroupInfo := range apiGroupInfos {
|
for _, apiGroupInfo := range apiGroupInfos {
|
||||||
apiGroupInfo.StaticOpenAPISpec = openAPISpec
|
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
|
// getResourceNamesForGroup is a private method for getting the canonical names for each resource to build in an api group
|
||||||
|
Loading…
Reference in New Issue
Block a user