diff --git a/cmd/internal/codegen/parse/crd.go b/cmd/internal/codegen/parse/crd.go index a275900562..d49c75fbee 100644 --- a/cmd/internal/codegen/parse/crd.go +++ b/cmd/internal/codegen/parse/crd.go @@ -41,8 +41,11 @@ func (b *APIs) parseCRDs() { for _, resource := range version.Resources { if IsAPIResource(resource.Type) { resource.JSONSchemaProps, resource.Validation = - b.typeToJSONSchemaProps(resource.Type, sets.NewString(), []string{}) - + b.typeToJSONSchemaProps(resource.Type, sets.NewString(), []string{}, true) + // k8s 1.11 rejects CRDs with type property at the root if status sub-resources enabled. + // This change drops the type field for CRD at the root level. Refer to issue below: + // https://github.com/kubernetes/kubernetes/issues/65293 + resource.JSONSchemaProps.Type = "" j, err := json.MarshalIndent(resource.JSONSchemaProps, "", " ") if err != nil { log.Fatalf("Could not Marshall validation %v\n", err) @@ -114,7 +117,7 @@ func (b *APIs) getMeta() string { // typeToJSONSchemaProps returns a JSONSchemaProps object and its serialization // in Go that describe the JSONSchema validations for the given type. -func (b *APIs) typeToJSONSchemaProps(t *types.Type, found sets.String, comments []string) (v1beta1.JSONSchemaProps, string) { +func (b *APIs) typeToJSONSchemaProps(t *types.Type, found sets.String, comments []string, isRoot bool) (v1beta1.JSONSchemaProps, string) { // Special cases time := types.Name{Name: "Time", Package: "k8s.io/apimachinery/pkg/apis/meta/v1"} meta := types.Name{Name: "ObjectMeta", Package: "k8s.io/apimachinery/pkg/apis/meta/v1"} @@ -136,7 +139,7 @@ func (b *APIs) typeToJSONSchemaProps(t *types.Type, found sets.String, comments case types.Builtin: v, s = b.parsePrimitiveValidation(t, found, comments) case types.Struct: - v, s = b.parseObjectValidation(t, found, comments) + v, s = b.parseObjectValidation(t, found, comments, isRoot) case types.Map: v, s = b.parseMapValidation(t, found, comments) case types.Slice: @@ -144,9 +147,9 @@ func (b *APIs) typeToJSONSchemaProps(t *types.Type, found sets.String, comments case types.Array: v, s = b.parseArrayValidation(t, found, comments) case types.Pointer: - v, s = b.typeToJSONSchemaProps(t.Elem, found, comments) + v, s = b.typeToJSONSchemaProps(t.Elem, found, comments, false) case types.Alias: - v, s = b.typeToJSONSchemaProps(t.Underlying, found, comments) + v, s = b.typeToJSONSchemaProps(t.Underlying, found, comments, false) default: log.Fatalf("Unknown supported Kind %v\n", t.Kind) } @@ -256,7 +259,7 @@ var mapTemplate = template.Must(template.New("map-template").Parse( // parseMapValidation returns a JSONSchemaProps object and its serialization in // Go that describe the validations for the given map type. func (b *APIs) parseMapValidation(t *types.Type, found sets.String, comments []string) (v1beta1.JSONSchemaProps, string) { - additionalProps, result := b.typeToJSONSchemaProps(t.Elem, found, comments) + additionalProps, result := b.typeToJSONSchemaProps(t.Elem, found, comments, false) props := v1beta1.JSONSchemaProps{ Type: "object", } @@ -304,7 +307,7 @@ type arrayTemplateArgs struct { // parseArrayValidation returns a JSONSchemaProps object and its serialization in // Go that describe the validations for the given array type. func (b *APIs) parseArrayValidation(t *types.Type, found sets.String, comments []string) (v1beta1.JSONSchemaProps, string) { - items, result := b.typeToJSONSchemaProps(t.Elem, found, comments) + items, result := b.typeToJSONSchemaProps(t.Elem, found, comments, false) props := v1beta1.JSONSchemaProps{ Type: "array", Items: &v1beta1.JSONSchemaPropsOrArray{Schema: &items}, @@ -330,11 +333,17 @@ type objectTemplateArgs struct { v1beta1.JSONSchemaProps Fields map[string]string Required []string + IsRoot bool } +// Drop the "type" field from the CRD validation schema at the root level. +// K8s 1.11 server rejects such CRDs. Refer to issue below for more details: +// https://github.com/kubernetes/kubernetes/issues/65293 var objectTemplate = template.Must(template.New("object-template").Parse( `v1beta1.JSONSchemaProps{ + {{ if not .IsRoot -}} Type: "object", + {{ end -}} Properties: map[string]v1beta1.JSONSchemaProps{ {{ range $k, $v := .Fields -}} "{{ $k }}": {{ $v }}, @@ -349,14 +358,14 @@ var objectTemplate = template.Must(template.New("object-template").Parse( // parseObjectValidation returns a JSONSchemaProps object and its serialization in // Go that describe the validations for the given object type. -func (b *APIs) parseObjectValidation(t *types.Type, found sets.String, comments []string) (v1beta1.JSONSchemaProps, string) { +func (b *APIs) parseObjectValidation(t *types.Type, found sets.String, comments []string, isRoot bool) (v1beta1.JSONSchemaProps, string) { buff := &bytes.Buffer{} props := v1beta1.JSONSchemaProps{ Type: "object", } if strings.HasPrefix(t.Name.String(), "k8s.io/api") { - if err := objectTemplate.Execute(buff, objectTemplateArgs{props, nil, nil}); err != nil { + if err := objectTemplate.Execute(buff, objectTemplateArgs{props, nil, nil, false}); err != nil { log.Fatalf("%v", err) } } else { @@ -369,7 +378,7 @@ func (b *APIs) parseObjectValidation(t *types.Type, found sets.String, comments getValidation(l, &props) } - if err := objectTemplate.Execute(buff, objectTemplateArgs{props, result, required}); err != nil { + if err := objectTemplate.Execute(buff, objectTemplateArgs{props, result, required, isRoot}); err != nil { log.Fatalf("%v", err) } } @@ -533,7 +542,7 @@ func (b *APIs) getMembers(t *types.Type, found sets.String) (map[string]v1beta1. } required = append(required, re...) } else { - m, r := b.typeToJSONSchemaProps(member.Type, found, member.CommentLines) + m, r := b.typeToJSONSchemaProps(member.Type, found, member.CommentLines, false) members[name] = m result[name] = r if !strings.HasSuffix(strat, "omitempty") { diff --git a/common.sh b/common.sh index 0b9cadada8..dde4d0f62b 100644 --- a/common.sh +++ b/common.sh @@ -42,6 +42,7 @@ cd "$base_dir" || { } k8s_version=1.10.1 +#k8s_version=1.11.0 goarch=amd64 goos="unknown" @@ -163,4 +164,4 @@ function dump_cache { if [ -d "$TEST_DEP" ]; then cp -r $TEST_DEP/* . fi -} \ No newline at end of file +} diff --git a/test/data/resource/expected/crd-expected.yaml b/test/data/resource/expected/crd-expected.yaml index 74715b5638..33974a715f 100644 --- a/test/data/resource/expected/crd-expected.yaml +++ b/test/data/resource/expected/crd-expected.yaml @@ -64,7 +64,6 @@ spec: type: object status: type: object - type: object version: v1beta1 status: acceptedNames: diff --git a/test/projects/memcached-api-server/test/hack/install.yaml b/test/projects/memcached-api-server/test/hack/install.yaml index f78ca098fb..c343c5ae2a 100644 --- a/test/projects/memcached-api-server/test/hack/install.yaml +++ b/test/projects/memcached-api-server/test/hack/install.yaml @@ -38,7 +38,6 @@ spec: type: string type: array type: object - type: object version: v1alpha1 status: acceptedNames: diff --git a/test/projects/validations/test/hack/install.yaml b/test/projects/validations/test/hack/install.yaml index 2f444cd551..65b0d13f1a 100644 --- a/test/projects/validations/test/hack/install.yaml +++ b/test/projects/validations/test/hack/install.yaml @@ -69,7 +69,6 @@ spec: type: object status: type: object - type: object version: v1 status: acceptedNames: diff --git a/test_existing_projects.sh b/test_existing_projects.sh index 0cea518f61..4603c9293f 100755 --- a/test_existing_projects.sh +++ b/test_existing_projects.sh @@ -20,6 +20,6 @@ set -o pipefail for p in ./test/projects/* do if [[ -d "$p" ]]; then - go test -v "$p" + go test -v -count=1 "$p" fi done diff --git a/testv0.sh b/testv0.sh index bee3e39a27..07e340e97f 100755 --- a/testv0.sh +++ b/testv0.sh @@ -86,7 +86,6 @@ spec: type: object status: type: object - type: object version: v1beta1 status: acceptedNames: @@ -184,7 +183,6 @@ spec: type: object status: type: object - type: object version: v1beta1 status: acceptedNames: @@ -293,7 +291,6 @@ spec: type: object status: type: object - type: object version: v1beta1 status: acceptedNames: @@ -336,7 +333,6 @@ spec: type: object status: type: object - type: object version: v1beta1 status: acceptedNames: @@ -371,7 +367,6 @@ spec: type: object status: type: object - type: object version: v1beta1 status: acceptedNames: