apiextensions: add structural schema extension unfolding
This commit is contained in:
		@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2019 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Unfold expands vendor extensions of a structural schema.
 | 
				
			||||||
 | 
					// It mutates the receiver.
 | 
				
			||||||
 | 
					func (s *Structural) Unfold() *Structural {
 | 
				
			||||||
 | 
						if s == nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mapper := Visitor{
 | 
				
			||||||
 | 
							Structural: func(s *Structural) bool {
 | 
				
			||||||
 | 
								if !s.XIntOrString {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								skipAnyOf := isIntOrStringAnyOfPattern(s)
 | 
				
			||||||
 | 
								skipFirstAllOfAnyOf := isIntOrStringAllOfPattern(s)
 | 
				
			||||||
 | 
								if skipAnyOf || skipFirstAllOfAnyOf {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if s.AnyOf == nil {
 | 
				
			||||||
 | 
									s.AnyOf = []NestedValueValidation{
 | 
				
			||||||
 | 
										{ForbiddenGenerics: Generic{Type: "integer"}},
 | 
				
			||||||
 | 
										{ForbiddenGenerics: Generic{Type: "string"}},
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									s.AllOf = append([]NestedValueValidation{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ValueValidation: ValueValidation{
 | 
				
			||||||
 | 
												AnyOf: []NestedValueValidation{
 | 
				
			||||||
 | 
													{ForbiddenGenerics: Generic{Type: "integer"}},
 | 
				
			||||||
 | 
													{ForbiddenGenerics: Generic{Type: "string"}},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									}, s.AllOf...)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							NestedValueValidation: nil, // x-kubernetes-int-or-string cannot be set in nested value validation
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mapper.Visit(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -97,15 +97,8 @@ func validateStructuralInvariants(s *Structural, lvl level, fldPath *field.Path)
 | 
				
			|||||||
	//      - type: integer
 | 
						//      - type: integer
 | 
				
			||||||
	//      - type: string
 | 
						//      - type: string
 | 
				
			||||||
	//    - ... zero or more
 | 
						//    - ... zero or more
 | 
				
			||||||
	skipAnyOf := false
 | 
						skipAnyOf := isIntOrStringAnyOfPattern(s)
 | 
				
			||||||
	skipFirstAllOfAnyOf := false
 | 
						skipFirstAllOfAnyOf := isIntOrStringAllOfPattern(s)
 | 
				
			||||||
	if s.XIntOrString && s.ValueValidation != nil {
 | 
					 | 
				
			||||||
		if len(s.ValueValidation.AnyOf) == 2 && reflect.DeepEqual(s.ValueValidation.AnyOf, intOrStringAnyOf) {
 | 
					 | 
				
			||||||
			skipAnyOf = true
 | 
					 | 
				
			||||||
		} else if len(s.ValueValidation.AllOf) >= 1 && len(s.ValueValidation.AllOf[0].AnyOf) == 2 && reflect.DeepEqual(s.ValueValidation.AllOf[0].AnyOf, intOrStringAnyOf) {
 | 
					 | 
				
			||||||
			skipFirstAllOfAnyOf = true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allErrs = append(allErrs, validateValueValidation(s.ValueValidation, skipAnyOf, skipFirstAllOfAnyOf, lvl, fldPath)...)
 | 
						allErrs = append(allErrs, validateValueValidation(s.ValueValidation, skipAnyOf, skipFirstAllOfAnyOf, lvl, fldPath)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -157,6 +150,20 @@ func validateStructuralInvariants(s *Structural, lvl level, fldPath *field.Path)
 | 
				
			|||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isIntOrStringAnyOfPattern(s *Structural) bool {
 | 
				
			||||||
 | 
						if s == nil || s.ValueValidation == nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return len(s.ValueValidation.AnyOf) == 2 && reflect.DeepEqual(s.ValueValidation.AnyOf, intOrStringAnyOf)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isIntOrStringAllOfPattern(s *Structural) bool {
 | 
				
			||||||
 | 
						if s == nil || s.ValueValidation == nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return len(s.ValueValidation.AllOf) >= 1 && len(s.ValueValidation.AllOf[0].AnyOf) == 2 && reflect.DeepEqual(s.ValueValidation.AllOf[0].AnyOf, intOrStringAnyOf)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// validateGeneric checks the generic fields of a structural schema.
 | 
					// validateGeneric checks the generic fields of a structural schema.
 | 
				
			||||||
func validateGeneric(g *Generic, lvl level, fldPath *field.Path) field.ErrorList {
 | 
					func validateGeneric(g *Generic, lvl level, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	if g == nil {
 | 
						if g == nil {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user