From 8ae4b537867711e5041cf3661d0a542b17945b9d Mon Sep 17 00:00:00 2001 From: jennybuckley Date: Thu, 24 May 2018 09:54:03 -0700 Subject: [PATCH] Update version of k8s.io/kube-openapi --- Godeps/Godeps.json | 16 ++-- .../kube-openapi/pkg/builder/openapi.go | 51 ++++++---- .../kube-openapi/pkg/generators/extension.go | 96 +++++++++++++++---- .../kube-openapi/pkg/generators/openapi.go | 11 +-- 4 files changed, 123 insertions(+), 51 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 7e937c367ea..6327cde93d6 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -3334,35 +3334,35 @@ }, { "ImportPath": "k8s.io/kube-openapi/pkg/aggregator", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/builder", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/common", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/generators", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/handler", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/util", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/util/proto", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/kube-openapi/pkg/util/proto/validation", - "Rev": "61db125d227fc9d4e373819a059516f32f7f23c7" + "Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5" }, { "ImportPath": "k8s.io/utils/clock", diff --git a/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go b/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go index 78714e8b2ae..e4fe7c62ed9 100644 --- a/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go +++ b/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go @@ -45,6 +45,32 @@ type openAPI struct { // BuildOpenAPISpec builds OpenAPI spec given a list of webservices (containing routes) and common.Config to customize it. func BuildOpenAPISpec(webServices []*restful.WebService, config *common.Config) (*spec.Swagger, error) { + o := newOpenAPI(config) + err := o.buildPaths(webServices) + if err != nil { + return nil, err + } + return o.finalizeSwagger() +} + +// BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it. +func BuildOpenAPIDefinitionsForResource(model interface{}, config *common.Config) (*spec.Definitions, error) { + o := newOpenAPI(config) + // We can discard the return value of toSchema because all we care about is the side effect of calling it. + // All the models created for this resource get added to o.swagger.Definitions + _, err := o.toSchema(model) + if err != nil { + return nil, err + } + swagger, err := o.finalizeSwagger() + if err != nil { + return nil, err + } + return &swagger.Definitions, nil +} + +// newOpenAPI sets up the openAPI object so we can build the spec. +func newOpenAPI(config *common.Config) openAPI { o := openAPI{ config: config, swagger: &spec.Swagger{ @@ -56,16 +82,6 @@ func BuildOpenAPISpec(webServices []*restful.WebService, config *common.Config) }, }, } - - err := o.init(webServices) - if err != nil { - return nil, err - } - - return o.swagger, nil -} - -func (o *openAPI) init(webServices []*restful.WebService) error { if o.config.GetOperationIDAndTags == nil { o.config.GetOperationIDAndTags = func(r *restful.Route) (string, []string, error) { return r.Operation, nil, nil @@ -83,22 +99,25 @@ func (o *openAPI) init(webServices []*restful.WebService) error { if o.config.CommonResponses == nil { o.config.CommonResponses = map[int]spec.Response{} } - err := o.buildPaths(webServices) - if err != nil { - return err - } + return o +} + +// finalizeSwagger is called after the spec is built and returns the final spec. +// NOTE: finalizeSwagger also make changes to the final spec, as specified in the config. +func (o *openAPI) finalizeSwagger() (*spec.Swagger, error) { if o.config.SecurityDefinitions != nil { o.swagger.SecurityDefinitions = *o.config.SecurityDefinitions o.swagger.Security = o.config.DefaultSecurity } if o.config.PostProcessSpec != nil { + var err error o.swagger, err = o.config.PostProcessSpec(o.swagger) if err != nil { - return err + return nil, err } } - return nil + return o.swagger, nil } func getCanonicalizeTypeName(t reflect.Type) string { diff --git a/vendor/k8s.io/kube-openapi/pkg/generators/extension.go b/vendor/k8s.io/kube-openapi/pkg/generators/extension.go index 7f3602408a3..befe38db248 100644 --- a/vendor/k8s.io/kube-openapi/pkg/generators/extension.go +++ b/vendor/k8s.io/kube-openapi/pkg/generators/extension.go @@ -27,18 +27,33 @@ import ( const extensionPrefix = "x-kubernetes-" -// Extension tag to openapi extension -var tagToExtension = map[string]string{ - "patchMergeKey": "x-kubernetes-patch-merge-key", - "patchStrategy": "x-kubernetes-patch-strategy", - "listType": "x-kubernetes-list-type", - "listMapKey": "x-kubernetes-list-map-keys", +// extensionAttributes encapsulates common traits for particular extensions. +type extensionAttributes struct { + xName string + kind types.Kind + allowedValues sets.String } -// Enum values per extension -var allowedExtensionValues = map[string]sets.String{ - "x-kubernetes-patch-strategy": sets.NewString("merge", "retainKeys"), - "x-kubernetes-list-type": sets.NewString("atomic", "set", "map"), +// Extension tag to openapi extension attributes +var tagToExtension = map[string]extensionAttributes{ + "patchMergeKey": extensionAttributes{ + xName: "x-kubernetes-patch-merge-key", + kind: types.Slice, + }, + "patchStrategy": extensionAttributes{ + xName: "x-kubernetes-patch-strategy", + kind: types.Slice, + allowedValues: sets.NewString("merge", "retainKeys"), + }, + "listMapKey": extensionAttributes{ + xName: "x-kubernetes-list-map-keys", + kind: types.Slice, + }, + "listType": extensionAttributes{ + xName: "x-kubernetes-list-type", + kind: types.Slice, + allowedValues: sets.NewString("atomic", "set", "map"), + }, } // Extension encapsulates information necessary to generate an OpenAPI extension. @@ -48,10 +63,25 @@ type extension struct { values []string // Example: [atomic] } +func (e extension) hasAllowedValues() bool { + return tagToExtension[e.idlTag].allowedValues.Len() > 0 +} + +func (e extension) allowedValues() sets.String { + return tagToExtension[e.idlTag].allowedValues +} + +func (e extension) hasKind() bool { + return len(tagToExtension[e.idlTag].kind) > 0 +} + +func (e extension) kind() types.Kind { + return tagToExtension[e.idlTag].kind +} + func (e extension) validateAllowedValues() error { // allowedValues not set means no restrictions on values. - allowedValues, exists := allowedExtensionValues[e.xName] - if !exists { + if !e.hasAllowedValues() { return nil } // Check for missing value. @@ -59,6 +89,7 @@ func (e extension) validateAllowedValues() error { return fmt.Errorf("%s needs a value, none given.", e.idlTag) } // For each extension value, validate that it is allowed. + allowedValues := e.allowedValues() if !allowedValues.HasAll(e.values...) { return fmt.Errorf("%v not allowed for %s. Allowed values: %v", e.values, e.idlTag, allowedValues.List()) @@ -66,6 +97,18 @@ func (e extension) validateAllowedValues() error { return nil } +func (e extension) validateType(kind types.Kind) error { + // If this extension class has no kind, then don't validate the type. + if !e.hasKind() { + return nil + } + if kind != e.kind() { + return fmt.Errorf("tag %s on type %v; only allowed on type %v", + e.idlTag, kind, e.kind()) + } + return nil +} + func (e extension) hasMultipleValues() bool { return len(e.values) > 1 } @@ -82,7 +125,9 @@ func sortedMapKeys(m map[string][]string) []string { return keys } -// Parses comments to return openapi extensions. +// Parses comments to return openapi extensions. Returns a list of +// extensions which parsed correctly, as well as a list of the +// parse errors. Validating extensions is performed separately. // NOTE: Non-empty errors does not mean extensions is empty. func parseExtensions(comments []string) ([]extension, []error) { extensions := []extension{} @@ -108,21 +153,30 @@ func parseExtensions(comments []string) ([]extension, []error) { // Next, generate extensions from "idlTags" (e.g. +listType) tagValues := types.ExtractCommentTags("+", comments) for _, idlTag := range sortedMapKeys(tagValues) { - xName, exists := tagToExtension[idlTag] + xAttrs, exists := tagToExtension[idlTag] if !exists { continue } values := tagValues[idlTag] e := extension{ - idlTag: idlTag, // listType - xName: xName, // x-kubernetes-list-type - values: values, // [atomic] - } - if err := e.validateAllowedValues(); err != nil { - // For now, only log the extension validation errors. - errors = append(errors, err) + idlTag: idlTag, // listType + xName: xAttrs.xName, // x-kubernetes-list-type + values: values, // [atomic] } extensions = append(extensions, e) } return extensions, errors } + +func validateMemberExtensions(extensions []extension, m *types.Member) []error { + errors := []error{} + for _, e := range extensions { + if err := e.validateAllowedValues(); err != nil { + errors = append(errors, err) + } + if err := e.validateType(m.Type.Kind); err != nil { + errors = append(errors, err) + } + } + return errors +} diff --git a/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go b/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go index deeac757197..13e1e0985af 100644 --- a/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go +++ b/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go @@ -432,7 +432,7 @@ func (g openAPITypeWriter) generateStructExtensions(t *types.Type) error { extensions, errors := parseExtensions(t.CommentLines) // Initially, we will only log struct extension errors. if len(errors) > 0 { - for e := range errors { + for _, e := range errors { glog.V(2).Infof("[%s]: %s\n", t.String(), e) } } @@ -442,17 +442,16 @@ func (g openAPITypeWriter) generateStructExtensions(t *types.Type) error { } func (g openAPITypeWriter) generateMemberExtensions(m *types.Member, parent *types.Type) error { - extensions, errors := parseExtensions(m.CommentLines) + extensions, parseErrors := parseExtensions(m.CommentLines) + validationErrors := validateMemberExtensions(extensions, m) + errors := append(parseErrors, validationErrors...) // Initially, we will only log member extension errors. if len(errors) > 0 { errorPrefix := fmt.Sprintf("[%s] %s:", parent.String(), m.String()) - for e := range errors { + for _, e := range errors { glog.V(2).Infof("%s %s\n", errorPrefix, e) } } - // TODO(seans3): Validate member extensions here. - // Example: listType extension is only on a Slice. - // Example: cross-extension validation - listMapKey only makes sense with listType=map g.emitExtensions(extensions) return nil }