mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-14 14:23:37 +00:00
add rest of accessors to common.Schema
needed for declarative validation, CRD ratcheting
This commit is contained in:
parent
89d822198f
commit
438c0daab7
@ -54,6 +54,13 @@ func (s *Structural) Format() string {
|
|||||||
return s.Structural.ValueValidation.Format
|
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 {
|
func (s *Structural) Items() common.Schema {
|
||||||
return &Structural{Structural: s.Structural.Items}
|
return &Structural{Structural: s.Structural.Items}
|
||||||
}
|
}
|
||||||
@ -81,6 +88,48 @@ func (s *Structural) Default() any {
|
|||||||
return s.Structural.Default.Object
|
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 {
|
func (s *Structural) MaxItems() *int64 {
|
||||||
if s.Structural.ValueValidation == nil {
|
if s.Structural.ValueValidation == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -88,6 +137,13 @@ func (s *Structural) MaxItems() *int64 {
|
|||||||
return s.Structural.ValueValidation.MaxItems
|
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 {
|
func (s *Structural) MaxLength() *int64 {
|
||||||
if s.Structural.ValueValidation == nil {
|
if s.Structural.ValueValidation == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -95,6 +151,13 @@ func (s *Structural) MaxLength() *int64 {
|
|||||||
return s.Structural.ValueValidation.MaxLength
|
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 {
|
func (s *Structural) MaxProperties() *int64 {
|
||||||
if s.Structural.ValueValidation == nil {
|
if s.Structural.ValueValidation == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -109,6 +172,12 @@ func (s *Structural) Required() []string {
|
|||||||
return s.Structural.ValueValidation.Required
|
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 {
|
func (s *Structural) Enum() []any {
|
||||||
if s.Structural.ValueValidation == nil {
|
if s.Structural.ValueValidation == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -143,10 +212,110 @@ func (s *Structural) XListType() string {
|
|||||||
return *s.Structural.XListType
|
return *s.Structural.XListType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Structural) XMapType() string {
|
||||||
|
if s.Structural.XMapType == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *s.Structural.XMapType
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Structural) XListMapKeys() []string {
|
func (s *Structural) XListMapKeys() []string {
|
||||||
return s.Structural.XListMapKeys
|
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 {
|
func (s *Structural) WithTypeAndObjectMeta() common.Schema {
|
||||||
return &Structural{Structural: WithTypeAndObjectMeta(s.Structural)}
|
return &Structural{Structural: WithTypeAndObjectMeta(s.Structural)}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,27 @@ type Schema interface {
|
|||||||
|
|
||||||
// Validations contains OpenAPI validation that the CEL library uses.
|
// Validations contains OpenAPI validation that the CEL library uses.
|
||||||
type Validations interface {
|
type Validations interface {
|
||||||
|
Pattern() string
|
||||||
|
Minimum() *float64
|
||||||
|
IsExclusiveMinimum() bool
|
||||||
|
Maximum() *float64
|
||||||
|
IsExclusiveMaximum() bool
|
||||||
|
MultipleOf() *float64
|
||||||
|
MinItems() *int64
|
||||||
MaxItems() *int64
|
MaxItems() *int64
|
||||||
|
MinLength() *int64
|
||||||
MaxLength() *int64
|
MaxLength() *int64
|
||||||
|
MinProperties() *int64
|
||||||
MaxProperties() *int64
|
MaxProperties() *int64
|
||||||
Required() []string
|
Required() []string
|
||||||
Enum() []any
|
Enum() []any
|
||||||
Nullable() bool
|
Nullable() bool
|
||||||
|
UniqueItems() bool
|
||||||
|
|
||||||
|
AllOf() []Schema
|
||||||
|
OneOf() []Schema
|
||||||
|
AnyOf() []Schema
|
||||||
|
Not() Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeExtensions contains Kubernetes-specific extensions to the OpenAPI schema.
|
// KubeExtensions contains Kubernetes-specific extensions to the OpenAPI schema.
|
||||||
@ -71,6 +86,16 @@ type KubeExtensions interface {
|
|||||||
IsXPreserveUnknownFields() bool
|
IsXPreserveUnknownFields() bool
|
||||||
XListType() string
|
XListType() string
|
||||||
XListMapKeys() []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
|
// SchemaOrBool contains either a schema or a boolean indicating if the object
|
||||||
|
@ -54,6 +54,10 @@ func (s *Schema) Format() string {
|
|||||||
return s.Schema.Format
|
return s.Schema.Format
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Schema) Pattern() string {
|
||||||
|
return s.Schema.Pattern
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Schema) Items() common.Schema {
|
func (s *Schema) Items() common.Schema {
|
||||||
if s.Schema.Items == nil || s.Schema.Items.Schema == nil {
|
if s.Schema.Items == nil || s.Schema.Items.Schema == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -86,14 +90,50 @@ func (s *Schema) Default() any {
|
|||||||
return s.Schema.Default
|
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 {
|
func (s *Schema) MaxItems() *int64 {
|
||||||
return s.Schema.MaxItems
|
return s.Schema.MaxItems
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Schema) MinLength() *int64 {
|
||||||
|
return s.Schema.MinLength
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Schema) MaxLength() *int64 {
|
func (s *Schema) MaxLength() *int64 {
|
||||||
return s.Schema.MaxLength
|
return s.Schema.MaxLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Schema) MinProperties() *int64 {
|
||||||
|
return s.Schema.MinProperties
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Schema) MaxProperties() *int64 {
|
func (s *Schema) MaxProperties() *int64 {
|
||||||
return s.Schema.MaxProperties
|
return s.Schema.MaxProperties
|
||||||
}
|
}
|
||||||
@ -110,6 +150,40 @@ func (s *Schema) Nullable() bool {
|
|||||||
return s.Schema.Nullable
|
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 {
|
func (s *Schema) IsXIntOrString() bool {
|
||||||
return isXIntOrString(s.Schema)
|
return isXIntOrString(s.Schema)
|
||||||
}
|
}
|
||||||
@ -126,10 +200,18 @@ func (s *Schema) XListType() string {
|
|||||||
return getXListType(s.Schema)
|
return getXListType(s.Schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Schema) XMapType() string {
|
||||||
|
return getXMapType(s.Schema)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Schema) XListMapKeys() []string {
|
func (s *Schema) XListMapKeys() []string {
|
||||||
return getXListMapKeys(s.Schema)
|
return getXListMapKeys(s.Schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Schema) XValidations() []common.ValidationRule {
|
||||||
|
return getXValidations(s.Schema)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Schema) WithTypeAndObjectMeta() common.Schema {
|
func (s *Schema) WithTypeAndObjectMeta() common.Schema {
|
||||||
return &Schema{common.WithTypeAndObjectMeta(s.Schema)}
|
return &Schema{common.WithTypeAndObjectMeta(s.Schema)}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package openapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
|
"k8s.io/apiserver/pkg/cel/common"
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -47,6 +48,11 @@ func getXListType(schema *spec.Schema) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getXMapType(schema *spec.Schema) string {
|
||||||
|
s, _ := schema.Extensions.GetString(extMapType)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func getXListMapKeys(schema *spec.Schema) []string {
|
func getXListMapKeys(schema *spec.Schema) []string {
|
||||||
mapKeys, ok := schema.Extensions.GetStringSlice(extListMapKeys)
|
mapKeys, ok := schema.Extensions.GetStringSlice(extListMapKeys)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -55,8 +61,47 @@ func getXListMapKeys(schema *spec.Schema) []string {
|
|||||||
return mapKeys
|
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 extIntOrString = "x-kubernetes-int-or-string"
|
||||||
const extEmbeddedResource = "x-kubernetes-embedded-resource"
|
const extEmbeddedResource = "x-kubernetes-embedded-resource"
|
||||||
const extPreserveUnknownFields = "x-kubernetes-preserve-unknown-fields"
|
const extPreserveUnknownFields = "x-kubernetes-preserve-unknown-fields"
|
||||||
const extListType = "x-kubernetes-list-type"
|
const extListType = "x-kubernetes-list-type"
|
||||||
|
const extMapType = "x-kubernetes-map-type"
|
||||||
const extListMapKeys = "x-kubernetes-list-map-keys"
|
const extListMapKeys = "x-kubernetes-list-map-keys"
|
||||||
|
const extValidations = "x-kubernetes-validations"
|
||||||
|
Loading…
Reference in New Issue
Block a user