apiextensions: prune {any,one}Of + Not recursively on OpenAPI v2 conversion

pull/58/head
Dr. Stefan Schimanski 2018-11-16 17:12:38 +01:00
parent e94a9f9321
commit 0d9a022533
6 changed files with 220 additions and 134 deletions

View File

@ -36,7 +36,6 @@ import (
"k8s.io/client-go/util/workqueue"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
informers "k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion/apiextensions/internalversion"
listers "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion"
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
@ -131,18 +130,10 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
if err != nil {
return err
}
// Convert internal CustomResourceValidation to versioned CustomResourceValidation
versionedSchema := new(v1beta1.CustomResourceValidation)
if validationSchema == nil {
versionedSchema = nil
} else {
if err := v1beta1.Convert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation(validationSchema, versionedSchema, nil); err != nil {
return err
}
}
// We aggregate the schema even if it's nil as it maybe a removal of the schema for this CRD,
// and the aggreated OpenAPI spec should reflect this change.
crdspec, etag, err := apiextensionsopenapi.CustomResourceDefinitionOpenAPISpec(&crd.Spec, version.Version, versionedSchema)
crdspec, etag, err := apiextensionsopenapi.CustomResourceDefinitionOpenAPISpec(&crd.Spec, version.Version, validationSchema)
if err != nil {
return err
}

View File

@ -50,8 +50,17 @@ func ValidateCustomResource(customResource interface{}, validator *validate.Sche
return nil
}
// ConvertJSONSchemaProps converts the schema from apiextensions.JSONSchemaPropos to go-openapi/spec.Schema
// ConvertJSONSchemaProps converts the schema from apiextensions.JSONSchemaPropos to go-openapi/spec.Schema.
func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema) error {
return ConvertJSONSchemaPropsWithPostProcess(in, out, nil)
}
// PostProcessFunc post-processes one node of a spec.Schema.
type PostProcessFunc func(*spec.Schema) error
// ConvertJSONSchemaPropsWithPostProcess converts the schema from apiextensions.JSONSchemaPropos to go-openapi/spec.Schema
// and run a post process step on each JSONSchemaProps node.
func ConvertJSONSchemaPropsWithPostProcess(in *apiextensions.JSONSchemaProps, out *spec.Schema, postProcess PostProcessFunc) error {
if in == nil {
return nil
}
@ -86,41 +95,43 @@ func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema)
out.Example = *(in.Example)
}
out.Enum = make([]interface{}, len(in.Enum))
for k, v := range in.Enum {
out.Enum[k] = v
if in.Enum != nil {
out.Enum = make([]interface{}, len(in.Enum))
for k, v := range in.Enum {
out.Enum[k] = v
}
}
if err := convertSliceOfJSONSchemaProps(&in.AllOf, &out.AllOf); err != nil {
if err := convertSliceOfJSONSchemaProps(&in.AllOf, &out.AllOf, postProcess); err != nil {
return err
}
if err := convertSliceOfJSONSchemaProps(&in.OneOf, &out.OneOf); err != nil {
if err := convertSliceOfJSONSchemaProps(&in.OneOf, &out.OneOf, postProcess); err != nil {
return err
}
if err := convertSliceOfJSONSchemaProps(&in.AnyOf, &out.AnyOf); err != nil {
if err := convertSliceOfJSONSchemaProps(&in.AnyOf, &out.AnyOf, postProcess); err != nil {
return err
}
if in.Not != nil {
in, out := &in.Not, &out.Not
*out = new(spec.Schema)
if err := ConvertJSONSchemaProps(*in, *out); err != nil {
if err := ConvertJSONSchemaPropsWithPostProcess(*in, *out, postProcess); err != nil {
return err
}
}
var err error
out.Properties, err = convertMapOfJSONSchemaProps(in.Properties)
out.Properties, err = convertMapOfJSONSchemaProps(in.Properties, postProcess)
if err != nil {
return err
}
out.PatternProperties, err = convertMapOfJSONSchemaProps(in.PatternProperties)
out.PatternProperties, err = convertMapOfJSONSchemaProps(in.PatternProperties, postProcess)
if err != nil {
return err
}
out.Definitions, err = convertMapOfJSONSchemaProps(in.Definitions)
out.Definitions, err = convertMapOfJSONSchemaProps(in.Definitions, postProcess)
if err != nil {
return err
}
@ -135,7 +146,7 @@ func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema)
if in.AdditionalProperties != nil {
in, out := &in.AdditionalProperties, &out.AdditionalProperties
*out = new(spec.SchemaOrBool)
if err := convertJSONSchemaPropsorBool(*in, *out); err != nil {
if err := convertJSONSchemaPropsorBool(*in, *out, postProcess); err != nil {
return err
}
}
@ -143,7 +154,7 @@ func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema)
if in.AdditionalItems != nil {
in, out := &in.AdditionalItems, &out.AdditionalItems
*out = new(spec.SchemaOrBool)
if err := convertJSONSchemaPropsorBool(*in, *out); err != nil {
if err := convertJSONSchemaPropsorBool(*in, *out, postProcess); err != nil {
return err
}
}
@ -151,7 +162,7 @@ func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = new(spec.SchemaOrArray)
if err := convertJSONSchemaPropsOrArray(*in, *out); err != nil {
if err := convertJSONSchemaPropsOrArray(*in, *out, postProcess); err != nil {
return err
}
}
@ -161,7 +172,7 @@ func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema)
*out = make(spec.Dependencies, len(*in))
for key, val := range *in {
newVal := new(spec.SchemaOrStringArray)
if err := convertJSONSchemaPropsOrStringArray(&val, newVal); err != nil {
if err := convertJSONSchemaPropsOrStringArray(&val, newVal, postProcess); err != nil {
return err
}
(*out)[key] = *newVal
@ -174,14 +185,20 @@ func ConvertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema)
out.ExternalDocs.URL = in.ExternalDocs.URL
}
if postProcess != nil {
if err := postProcess(out); err != nil {
return err
}
}
return nil
}
func convertSliceOfJSONSchemaProps(in *[]apiextensions.JSONSchemaProps, out *[]spec.Schema) error {
func convertSliceOfJSONSchemaProps(in *[]apiextensions.JSONSchemaProps, out *[]spec.Schema, postProcess PostProcessFunc) error {
if in != nil {
for _, jsonSchemaProps := range *in {
schema := spec.Schema{}
if err := ConvertJSONSchemaProps(&jsonSchemaProps, &schema); err != nil {
if err := ConvertJSONSchemaPropsWithPostProcess(&jsonSchemaProps, &schema, postProcess); err != nil {
return err
}
*out = append(*out, schema)
@ -190,25 +207,27 @@ func convertSliceOfJSONSchemaProps(in *[]apiextensions.JSONSchemaProps, out *[]s
return nil
}
func convertMapOfJSONSchemaProps(in map[string]apiextensions.JSONSchemaProps) (map[string]spec.Schema, error) {
func convertMapOfJSONSchemaProps(in map[string]apiextensions.JSONSchemaProps, postProcess PostProcessFunc) (map[string]spec.Schema, error) {
if in == nil {
return nil, nil
}
out := make(map[string]spec.Schema)
if len(in) != 0 {
for k, jsonSchemaProps := range in {
schema := spec.Schema{}
if err := ConvertJSONSchemaProps(&jsonSchemaProps, &schema); err != nil {
return nil, err
}
out[k] = schema
for k, jsonSchemaProps := range in {
schema := spec.Schema{}
if err := ConvertJSONSchemaPropsWithPostProcess(&jsonSchemaProps, &schema, postProcess); err != nil {
return nil, err
}
out[k] = schema
}
return out, nil
}
func convertJSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out *spec.SchemaOrArray) error {
func convertJSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out *spec.SchemaOrArray, postProcess PostProcessFunc) error {
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(spec.Schema)
if err := ConvertJSONSchemaProps(*in, *out); err != nil {
if err := ConvertJSONSchemaPropsWithPostProcess(*in, *out, postProcess); err != nil {
return err
}
}
@ -216,7 +235,7 @@ func convertJSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out
in, out := &in.JSONSchemas, &out.Schemas
*out = make([]spec.Schema, len(*in))
for i := range *in {
if err := ConvertJSONSchemaProps(&(*in)[i], &(*out)[i]); err != nil {
if err := ConvertJSONSchemaPropsWithPostProcess(&(*in)[i], &(*out)[i], postProcess); err != nil {
return err
}
}
@ -224,24 +243,24 @@ func convertJSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out
return nil
}
func convertJSONSchemaPropsorBool(in *apiextensions.JSONSchemaPropsOrBool, out *spec.SchemaOrBool) error {
func convertJSONSchemaPropsorBool(in *apiextensions.JSONSchemaPropsOrBool, out *spec.SchemaOrBool, postProcess PostProcessFunc) error {
out.Allows = in.Allows
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(spec.Schema)
if err := ConvertJSONSchemaProps(*in, *out); err != nil {
if err := ConvertJSONSchemaPropsWithPostProcess(*in, *out, postProcess); err != nil {
return err
}
}
return nil
}
func convertJSONSchemaPropsOrStringArray(in *apiextensions.JSONSchemaPropsOrStringArray, out *spec.SchemaOrStringArray) error {
func convertJSONSchemaPropsOrStringArray(in *apiextensions.JSONSchemaPropsOrStringArray, out *spec.SchemaOrStringArray, postProcess PostProcessFunc) error {
out.Property = in.Property
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(spec.Schema)
if err := ConvertJSONSchemaProps(*in, *out); err != nil {
if err := ConvertJSONSchemaPropsWithPostProcess(*in, *out, postProcess); err != nil {
return err
}
}

View File

@ -14,7 +14,7 @@ go_library(
deps = [
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/github.com/go-openapi/spec:go_default_library",
@ -28,7 +28,8 @@ go_test(
srcs = ["conversion_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/github.com/go-openapi/spec:go_default_library",
],
)

View File

@ -17,33 +17,29 @@ limitations under the License.
package openapi
import (
"encoding/json"
"github.com/go-openapi/spec"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
)
// ConvertJSONSchemaPropsToOpenAPIv2Schema converts our internal OpenAPI v3 schema
// (*apiextensions.JSONSchemaProps) to an OpenAPI v2 schema (*spec.Schema).
// NOTE: we use versioned type (v1beta1) here so that we can properly marshal the object
// using the JSON tags
func ConvertJSONSchemaPropsToOpenAPIv2Schema(in *v1beta1.JSONSchemaProps) (*spec.Schema, error) {
func ConvertJSONSchemaPropsToOpenAPIv2Schema(in *apiextensions.JSONSchemaProps) (*spec.Schema, error) {
if in == nil {
return nil, nil
}
// Marshal JSONSchemaProps into JSON and unmarshal the data into spec.Schema
data, err := json.Marshal(*in)
if err != nil {
return nil, err
}
out := new(spec.Schema)
if err := out.UnmarshalJSON(data); err != nil {
return nil, err
}
// Remove unsupported fields in OpenAPI v2
out.OneOf = nil
out.AnyOf = nil
out.Not = nil
validation.ConvertJSONSchemaPropsWithPostProcess(in, out, func(p *spec.Schema) error {
// Remove unsupported fields in OpenAPI v2
p.OneOf = nil
p.AnyOf = nil
p.Not = nil
return nil
})
return out, nil
}

View File

@ -17,12 +17,12 @@ limitations under the License.
package openapi
import (
"encoding/json"
"reflect"
"testing"
"github.com/go-openapi/spec"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apimachinery/pkg/util/diff"
)
func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
@ -30,18 +30,16 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
testStr2 := "test2"
testFloat64 := float64(6.4)
testInt64 := int64(64)
raw, _ := json.Marshal(testStr)
raw2, _ := json.Marshal(testStr2)
testApiextensionsJSON := v1beta1.JSON{Raw: raw}
testApiextensionsJSON := apiextensions.JSON(testStr)
tests := []struct {
name string
in *v1beta1.JSONSchemaProps
in *apiextensions.JSONSchemaProps
expected *spec.Schema
}{
{
name: "id",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
ID: testStr,
},
expected: new(spec.Schema).
@ -49,7 +47,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "$schema",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Schema: "test",
},
expected: &spec.Schema{
@ -60,14 +58,14 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "$ref",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Ref: &testStr,
},
expected: spec.RefSchema(testStr),
},
{
name: "description",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Description: testStr,
},
expected: new(spec.Schema).
@ -75,7 +73,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "type and format",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Type: testStr,
Format: testStr2,
},
@ -84,7 +82,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "title",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Title: testStr,
},
expected: new(spec.Schema).
@ -92,7 +90,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "default",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Default: &testApiextensionsJSON,
},
expected: new(spec.Schema).
@ -100,7 +98,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "maximum and exclusiveMaximum",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Maximum: &testFloat64,
ExclusiveMaximum: true,
},
@ -109,7 +107,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "minimum and exclusiveMinimum",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Minimum: &testFloat64,
ExclusiveMinimum: true,
},
@ -118,7 +116,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "maxLength",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MaxLength: &testInt64,
},
expected: new(spec.Schema).
@ -126,7 +124,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "minLength",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MinLength: &testInt64,
},
expected: new(spec.Schema).
@ -134,7 +132,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "pattern",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Pattern: testStr,
},
expected: new(spec.Schema).
@ -142,7 +140,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "maxItems",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MaxItems: &testInt64,
},
expected: new(spec.Schema).
@ -150,7 +148,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "minItems",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MinItems: &testInt64,
},
expected: new(spec.Schema).
@ -158,7 +156,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "uniqueItems",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
UniqueItems: true,
},
expected: new(spec.Schema).
@ -166,7 +164,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "multipleOf",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MultipleOf: &testFloat64,
},
expected: new(spec.Schema).
@ -174,15 +172,15 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "enum",
in: &v1beta1.JSONSchemaProps{
Enum: []v1beta1.JSON{{Raw: raw}, {Raw: raw2}},
in: &apiextensions.JSONSchemaProps{
Enum: []apiextensions.JSON{apiextensions.JSON(testStr), apiextensions.JSON(testStr2)},
},
expected: new(spec.Schema).
WithEnum(testStr, testStr2),
},
{
name: "maxProperties",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MaxProperties: &testInt64,
},
expected: new(spec.Schema).
@ -190,7 +188,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "minProperties",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
MinProperties: &testInt64,
},
expected: new(spec.Schema).
@ -198,7 +196,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "required",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Required: []string{testStr, testStr2},
},
expected: new(spec.Schema).
@ -206,9 +204,9 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "items single props",
in: &v1beta1.JSONSchemaProps{
Items: &v1beta1.JSONSchemaPropsOrArray{
Schema: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "boolean",
},
},
@ -223,9 +221,9 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "items array props",
in: &v1beta1.JSONSchemaProps{
Items: &v1beta1.JSONSchemaPropsOrArray{
JSONSchemas: []v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Items: &apiextensions.JSONSchemaPropsOrArray{
JSONSchemas: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
@ -244,8 +242,8 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "allOf",
in: &v1beta1.JSONSchemaProps{
AllOf: []v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
AllOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
@ -255,8 +253,8 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "oneOf",
in: &v1beta1.JSONSchemaProps{
OneOf: []v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
OneOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
@ -273,8 +271,8 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "anyOf",
in: &v1beta1.JSONSchemaProps{
AnyOf: []v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
AnyOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
@ -291,8 +289,8 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "not",
in: &v1beta1.JSONSchemaProps{
Not: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Not: &apiextensions.JSONSchemaProps{
Type: "boolean",
},
},
@ -303,10 +301,90 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
// },
// },
},
{
name: "nested logic",
in: &apiextensions.JSONSchemaProps{
AllOf: []apiextensions.JSONSchemaProps{
{
Not: &apiextensions.JSONSchemaProps{
Type: "boolean",
},
},
{
AnyOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
{
OneOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
{Type: "string"},
},
AnyOf: []apiextensions.JSONSchemaProps{
{
Not: &apiextensions.JSONSchemaProps{
Type: "boolean",
},
},
{
AnyOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
{
OneOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
{Type: "string"},
},
OneOf: []apiextensions.JSONSchemaProps{
{
Not: &apiextensions.JSONSchemaProps{
Type: "boolean",
},
},
{
AnyOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
{
OneOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
{Type: "string"},
},
Not: &apiextensions.JSONSchemaProps{
Not: &apiextensions.JSONSchemaProps{
Type: "boolean",
},
AnyOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
OneOf: []apiextensions.JSONSchemaProps{
{Type: "boolean"},
{Type: "string"},
},
},
},
expected: new(spec.Schema).
WithAllOf(spec.Schema{}, spec.Schema{}, spec.Schema{}, *spec.StringProperty()),
},
{
name: "properties",
in: &v1beta1.JSONSchemaProps{
Properties: map[string]v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Properties: map[string]apiextensions.JSONSchemaProps{
testStr: {Type: "boolean"},
},
},
@ -315,10 +393,10 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "additionalProperties",
in: &v1beta1.JSONSchemaProps{
AdditionalProperties: &v1beta1.JSONSchemaPropsOrBool{
in: &apiextensions.JSONSchemaProps{
AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
Allows: true,
Schema: &v1beta1.JSONSchemaProps{Type: "boolean"},
Schema: &apiextensions.JSONSchemaProps{Type: "boolean"},
},
},
expected: &spec.Schema{
@ -332,8 +410,8 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "patternProperties",
in: &v1beta1.JSONSchemaProps{
PatternProperties: map[string]v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
PatternProperties: map[string]apiextensions.JSONSchemaProps{
testStr: {Type: "boolean"},
},
},
@ -347,10 +425,10 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "dependencies schema",
in: &v1beta1.JSONSchemaProps{
Dependencies: v1beta1.JSONSchemaDependencies{
testStr: v1beta1.JSONSchemaPropsOrStringArray{
Schema: &v1beta1.JSONSchemaProps{Type: "boolean"},
in: &apiextensions.JSONSchemaProps{
Dependencies: apiextensions.JSONSchemaDependencies{
testStr: apiextensions.JSONSchemaPropsOrStringArray{
Schema: &apiextensions.JSONSchemaProps{Type: "boolean"},
},
},
},
@ -366,9 +444,9 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "dependencies string array",
in: &v1beta1.JSONSchemaProps{
Dependencies: v1beta1.JSONSchemaDependencies{
testStr: v1beta1.JSONSchemaPropsOrStringArray{
in: &apiextensions.JSONSchemaProps{
Dependencies: apiextensions.JSONSchemaDependencies{
testStr: apiextensions.JSONSchemaPropsOrStringArray{
Property: []string{testStr2},
},
},
@ -385,10 +463,10 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "additionalItems",
in: &v1beta1.JSONSchemaProps{
AdditionalItems: &v1beta1.JSONSchemaPropsOrBool{
in: &apiextensions.JSONSchemaProps{
AdditionalItems: &apiextensions.JSONSchemaPropsOrBool{
Allows: true,
Schema: &v1beta1.JSONSchemaProps{Type: "boolean"},
Schema: &apiextensions.JSONSchemaProps{Type: "boolean"},
},
},
expected: &spec.Schema{
@ -402,9 +480,9 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "definitions",
in: &v1beta1.JSONSchemaProps{
Definitions: v1beta1.JSONSchemaDefinitions{
testStr: v1beta1.JSONSchemaProps{Type: "boolean"},
in: &apiextensions.JSONSchemaProps{
Definitions: apiextensions.JSONSchemaDefinitions{
testStr: apiextensions.JSONSchemaProps{Type: "boolean"},
},
},
expected: &spec.Schema{
@ -417,8 +495,8 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "externalDocs",
in: &v1beta1.JSONSchemaProps{
ExternalDocs: &v1beta1.ExternalDocumentation{
in: &apiextensions.JSONSchemaProps{
ExternalDocs: &apiextensions.ExternalDocumentation{
Description: testStr,
URL: testStr2,
},
@ -428,7 +506,7 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
},
{
name: "example",
in: &v1beta1.JSONSchemaProps{
in: &apiextensions.JSONSchemaProps{
Example: &testApiextensionsJSON,
},
expected: new(spec.Schema).
@ -437,12 +515,14 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2Schema(t *testing.T) {
}
for _, test := range tests {
out, err := ConvertJSONSchemaPropsToOpenAPIv2Schema(test.in)
if err != nil {
t.Errorf("unexpected error in converting openapi schema: %v", test.name)
}
if !reflect.DeepEqual(out, test.expected) {
t.Errorf("result of conversion test '%v' didn't match, want: %v; got: %v", test.name, *test.expected, *out)
}
t.Run(test.name, func(t *testing.T) {
out, err := ConvertJSONSchemaPropsToOpenAPIv2Schema(test.in)
if err != nil {
t.Fatalf("unexpected error in converting openapi schema: %v", err)
}
if !reflect.DeepEqual(*out, *test.expected) {
t.Errorf("unexpected result:\n want=%v\n got=%v\n\n%s", *test.expected, *out, diff.ObjectDiff(*test.expected, *out))
}
})
}
}

View File

@ -24,7 +24,6 @@ import (
"github.com/go-openapi/spec"
autoscalingv1 "k8s.io/api/autoscaling/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -206,7 +205,7 @@ func scaleStatusSchema() *spec.Schema {
// NOTE: in apiserver we general operates on internal types. We are using versioned (v1beta1)
// validation schema here because we need the json tags to properly marshal the object to
// JSON.
func CustomResourceDefinitionOpenAPISpec(crdSpec *apiextensions.CustomResourceDefinitionSpec, version string, validationSchema *v1beta1.CustomResourceValidation) (*spec.Swagger, string, error) {
func CustomResourceDefinitionOpenAPISpec(crdSpec *apiextensions.CustomResourceDefinitionSpec, version string, validationSchema *apiextensions.CustomResourceValidation) (*spec.Swagger, string, error) {
schema := &spec.Schema{}
if validationSchema != nil && validationSchema.OpenAPIV3Schema != nil {
var err error