mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-02 17:57:33 +00:00
Merge pull request #114792 from apelisse/typeconverter-swagger
Hide OpenAPI details behind the NewTypeConverter
This commit is contained in:
@@ -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
|
||||||
|
Reference in New Issue
Block a user