diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_discovery_controller.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_discovery_controller.go index da54fca6af5..2e03f0ae3b3 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_discovery_controller.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_discovery_controller.go @@ -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 } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation/validation.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation/validation.go index 558ddb1fcdc..99ee9211650 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation/validation.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation/validation.go @@ -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 } } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/BUILD b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/BUILD index d1d11eabec9..659ef33b7c4 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/BUILD +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/BUILD @@ -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", ], ) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion.go index 61853acb2ff..db425892fe6 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion.go @@ -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 } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion_test.go index d8c330280b6..6628ad81368 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/conversion_test.go @@ -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)) + } + }) } } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/swagger_util.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/swagger_util.go index 797fbeddc3a..13e479d7ca2 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/swagger_util.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/openapi/swagger_util.go @@ -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