Merge pull request #121096 from alexzielenski/common-schema

add rest of accessors to common.Schema
This commit is contained in:
Kubernetes Prow Robot 2023-10-14 00:00:54 +02:00 committed by GitHub
commit 088f8c0ec5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 321 additions and 0 deletions

View File

@ -54,6 +54,13 @@ func (s *Structural) Format() string {
return s.Structural.ValueValidation.Format
}
func (s *Structural) Pattern() string {
if s.Structural.ValueValidation == nil {
return ""
}
return s.Structural.ValueValidation.Pattern
}
func (s *Structural) Items() common.Schema {
return &Structural{Structural: s.Structural.Items}
}
@ -81,6 +88,48 @@ func (s *Structural) Default() any {
return s.Structural.Default.Object
}
func (s *Structural) Minimum() *float64 {
if s.Structural.ValueValidation == nil {
return nil
}
return s.Structural.ValueValidation.Minimum
}
func (s *Structural) IsExclusiveMinimum() bool {
if s.Structural.ValueValidation == nil {
return false
}
return s.Structural.ValueValidation.ExclusiveMinimum
}
func (s *Structural) Maximum() *float64 {
if s.Structural.ValueValidation == nil {
return nil
}
return s.Structural.ValueValidation.Maximum
}
func (s *Structural) IsExclusiveMaximum() bool {
if s.Structural.ValueValidation == nil {
return false
}
return s.Structural.ValueValidation.ExclusiveMaximum
}
func (s *Structural) MultipleOf() *float64 {
if s.Structural.ValueValidation == nil {
return nil
}
return s.Structural.ValueValidation.MultipleOf
}
func (s *Structural) MinItems() *int64 {
if s.Structural.ValueValidation == nil {
return nil
}
return s.Structural.ValueValidation.MinItems
}
func (s *Structural) MaxItems() *int64 {
if s.Structural.ValueValidation == nil {
return nil
@ -88,6 +137,13 @@ func (s *Structural) MaxItems() *int64 {
return s.Structural.ValueValidation.MaxItems
}
func (s *Structural) MinLength() *int64 {
if s.Structural.ValueValidation == nil {
return nil
}
return s.Structural.ValueValidation.MinLength
}
func (s *Structural) MaxLength() *int64 {
if s.Structural.ValueValidation == nil {
return nil
@ -95,6 +151,13 @@ func (s *Structural) MaxLength() *int64 {
return s.Structural.ValueValidation.MaxLength
}
func (s *Structural) MinProperties() *int64 {
if s.Structural.ValueValidation == nil {
return nil
}
return s.Structural.ValueValidation.MinProperties
}
func (s *Structural) MaxProperties() *int64 {
if s.Structural.ValueValidation == nil {
return nil
@ -109,6 +172,12 @@ func (s *Structural) Required() []string {
return s.Structural.ValueValidation.Required
}
func (s *Structural) UniqueItems() bool {
// This field is forbidden in structural schema.
// but you can just you x-kubernetes-list-type:set to get around it :)
return false
}
func (s *Structural) Enum() []any {
if s.Structural.ValueValidation == nil {
return nil
@ -143,10 +212,110 @@ func (s *Structural) XListType() string {
return *s.Structural.XListType
}
func (s *Structural) XMapType() string {
if s.Structural.XMapType == nil {
return ""
}
return *s.Structural.XMapType
}
func (s *Structural) XListMapKeys() []string {
return s.Structural.XListMapKeys
}
func (s *Structural) AllOf() []common.Schema {
var res []common.Schema
for _, subSchema := range s.Structural.ValueValidation.AllOf {
subSchema := subSchema
res = append(res, nestedValueValidationToStructural(&subSchema))
}
return res
}
func (s *Structural) AnyOf() []common.Schema {
var res []common.Schema
for _, subSchema := range s.Structural.ValueValidation.AnyOf {
subSchema := subSchema
res = append(res, nestedValueValidationToStructural(&subSchema))
}
return res
}
func (s *Structural) OneOf() []common.Schema {
var res []common.Schema
for _, subSchema := range s.Structural.ValueValidation.OneOf {
subSchema := subSchema
res = append(res, nestedValueValidationToStructural(&subSchema))
}
return res
}
func (s *Structural) Not() common.Schema {
if s.Structural.ValueValidation.Not == nil {
return nil
}
return nestedValueValidationToStructural(s.Structural.ValueValidation.Not)
}
// nestedValueValidationToStructural converts a nested value validation to
// an equivalent structural schema instance.
//
// This lets us avoid needing a separate adaptor for the nested value
// validations, and doesn't cost too much since since we are usually exploring the
// entire schema anyway.
func nestedValueValidationToStructural(nvv *schema.NestedValueValidation) *Structural {
var newItems *schema.Structural
if nvv.Items != nil {
newItems = nestedValueValidationToStructural(nvv.Items).Structural
}
var newProperties map[string]schema.Structural
for k, v := range nvv.Properties {
if newProperties == nil {
newProperties = make(map[string]schema.Structural)
}
v := v
newProperties[k] = *nestedValueValidationToStructural(&v).Structural
}
return &Structural{
Structural: &schema.Structural{
Items: newItems,
Properties: newProperties,
ValueValidation: &nvv.ValueValidation,
},
}
}
type StructuralValidationRule struct {
rule, message, messageExpression, fieldPath string
}
func (s *StructuralValidationRule) Rule() string {
return s.rule
}
func (s *StructuralValidationRule) Message() string {
return s.message
}
func (s *StructuralValidationRule) FieldPath() string {
return s.fieldPath
}
func (s *StructuralValidationRule) MessageExpression() string {
return s.messageExpression
}
func (s *Structural) XValidations() []common.ValidationRule {
if len(s.Structural.XValidations) == 0 {
return nil
}
result := make([]common.ValidationRule, len(s.Structural.XValidations))
for i, v := range s.Structural.XValidations {
result[i] = &StructuralValidationRule{rule: v.Rule, message: v.Message, messageExpression: v.MessageExpression, fieldPath: v.FieldPath}
}
return result
}
func (s *Structural) WithTypeAndObjectMeta() common.Schema {
return &Structural{Structural: WithTypeAndObjectMeta(s.Structural)}
}

View File

@ -56,12 +56,27 @@ type Schema interface {
// Validations contains OpenAPI validation that the CEL library uses.
type Validations interface {
Pattern() string
Minimum() *float64
IsExclusiveMinimum() bool
Maximum() *float64
IsExclusiveMaximum() bool
MultipleOf() *float64
MinItems() *int64
MaxItems() *int64
MinLength() *int64
MaxLength() *int64
MinProperties() *int64
MaxProperties() *int64
Required() []string
Enum() []any
Nullable() bool
UniqueItems() bool
AllOf() []Schema
OneOf() []Schema
AnyOf() []Schema
Not() Schema
}
// KubeExtensions contains Kubernetes-specific extensions to the OpenAPI schema.
@ -71,6 +86,16 @@ type KubeExtensions interface {
IsXPreserveUnknownFields() bool
XListType() string
XListMapKeys() []string
XMapType() string
XValidations() []ValidationRule
}
// ValidationRule represents a single x-kubernetes-validations rule.
type ValidationRule interface {
Rule() string
Message() string
MessageExpression() string
FieldPath() string
}
// SchemaOrBool contains either a schema or a boolean indicating if the object

View File

@ -54,6 +54,10 @@ func (s *Schema) Format() string {
return s.Schema.Format
}
func (s *Schema) Pattern() string {
return s.Schema.Pattern
}
func (s *Schema) Items() common.Schema {
if s.Schema.Items == nil || s.Schema.Items.Schema == nil {
return nil
@ -86,14 +90,50 @@ func (s *Schema) Default() any {
return s.Schema.Default
}
func (s *Schema) Minimum() *float64 {
return s.Schema.Minimum
}
func (s *Schema) IsExclusiveMinimum() bool {
return s.Schema.ExclusiveMinimum
}
func (s *Schema) Maximum() *float64 {
return s.Schema.Maximum
}
func (s *Schema) IsExclusiveMaximum() bool {
return s.Schema.ExclusiveMaximum
}
func (s *Schema) MultipleOf() *float64 {
return s.Schema.MultipleOf
}
func (s *Schema) UniqueItems() bool {
return s.Schema.UniqueItems
}
func (s *Schema) MinItems() *int64 {
return s.Schema.MinItems
}
func (s *Schema) MaxItems() *int64 {
return s.Schema.MaxItems
}
func (s *Schema) MinLength() *int64 {
return s.Schema.MinLength
}
func (s *Schema) MaxLength() *int64 {
return s.Schema.MaxLength
}
func (s *Schema) MinProperties() *int64 {
return s.Schema.MinProperties
}
func (s *Schema) MaxProperties() *int64 {
return s.Schema.MaxProperties
}
@ -110,6 +150,40 @@ func (s *Schema) Nullable() bool {
return s.Schema.Nullable
}
func (s *Schema) AllOf() []common.Schema {
var res []common.Schema
for _, nestedSchema := range s.Schema.AllOf {
nestedSchema := nestedSchema
res = append(res, &Schema{&nestedSchema})
}
return res
}
func (s *Schema) AnyOf() []common.Schema {
var res []common.Schema
for _, nestedSchema := range s.Schema.AnyOf {
nestedSchema := nestedSchema
res = append(res, &Schema{&nestedSchema})
}
return res
}
func (s *Schema) OneOf() []common.Schema {
var res []common.Schema
for _, nestedSchema := range s.Schema.OneOf {
nestedSchema := nestedSchema
res = append(res, &Schema{&nestedSchema})
}
return res
}
func (s *Schema) Not() common.Schema {
if s.Schema.Not == nil {
return nil
}
return &Schema{s.Schema.Not}
}
func (s *Schema) IsXIntOrString() bool {
return isXIntOrString(s.Schema)
}
@ -126,10 +200,18 @@ func (s *Schema) XListType() string {
return getXListType(s.Schema)
}
func (s *Schema) XMapType() string {
return getXMapType(s.Schema)
}
func (s *Schema) XListMapKeys() []string {
return getXListMapKeys(s.Schema)
}
func (s *Schema) XValidations() []common.ValidationRule {
return getXValidations(s.Schema)
}
func (s *Schema) WithTypeAndObjectMeta() common.Schema {
return &Schema{common.WithTypeAndObjectMeta(s.Schema)}
}

View File

@ -18,6 +18,7 @@ package openapi
import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apiserver/pkg/cel/common"
"k8s.io/kube-openapi/pkg/validation/spec"
)
@ -47,6 +48,11 @@ func getXListType(schema *spec.Schema) string {
return s
}
func getXMapType(schema *spec.Schema) string {
s, _ := schema.Extensions.GetString(extMapType)
return s
}
func getXListMapKeys(schema *spec.Schema) []string {
mapKeys, ok := schema.Extensions.GetStringSlice(extListMapKeys)
if !ok {
@ -55,8 +61,47 @@ func getXListMapKeys(schema *spec.Schema) []string {
return mapKeys
}
type ValidationRule struct {
RuleField string `json:"rule"`
MessageField string `json:"message"`
MessageExpressionField string `json:"messageExpression"`
PathField string `json:"fieldPath"`
}
func (v ValidationRule) Rule() string {
return v.RuleField
}
func (v ValidationRule) Message() string {
return v.MessageField
}
func (v ValidationRule) FieldPath() string {
return v.PathField
}
func (v ValidationRule) MessageExpression() string {
return v.MessageExpressionField
}
// TODO: simplify
func getXValidations(schema *spec.Schema) []common.ValidationRule {
var rules []ValidationRule
err := schema.Extensions.GetObject(extValidations, &rules)
if err != nil {
return nil
}
results := make([]common.ValidationRule, len(rules))
for i, rule := range rules {
results[i] = rule
}
return results
}
const extIntOrString = "x-kubernetes-int-or-string"
const extEmbeddedResource = "x-kubernetes-embedded-resource"
const extPreserveUnknownFields = "x-kubernetes-preserve-unknown-fields"
const extListType = "x-kubernetes-list-type"
const extMapType = "x-kubernetes-map-type"
const extListMapKeys = "x-kubernetes-list-map-keys"
const extValidations = "x-kubernetes-validations"