Merge remote-tracking branch 'origin/master' into release-1.11

Kubernetes-commit: 4e3b2843df571c3b80c834d7c23bc6da1a22aab8
This commit is contained in:
Kubernetes Publisher
2018-05-31 14:24:28 -04:00
27 changed files with 1945 additions and 1277 deletions
+2 -2
View File
@@ -260,11 +260,11 @@
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/common",
"Rev": "61db125d227fc9d4e373819a059516f32f7f23c7"
"Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5"
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/generators",
"Rev": "61db125d227fc9d4e373819a059516f32f7f23c7"
"Rev": "86e28c192d2743f0232b9bc5f0a531568ef9f2a5"
}
]
}
@@ -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
}
@@ -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
}