1
16
17 package validation
18
19 import (
20 "reflect"
21
22 "k8s.io/apiserver/pkg/cel/common"
23 celopenapi "k8s.io/apiserver/pkg/cel/openapi"
24 "k8s.io/kube-openapi/pkg/validation/spec"
25 "k8s.io/kube-openapi/pkg/validation/strfmt"
26 "k8s.io/kube-openapi/pkg/validation/validate"
27 )
28
29
30
31 type schemaArgs struct {
32 schema *spec.Schema
33 root interface{}
34 path string
35 knownFormats strfmt.Registry
36 options []validate.Option
37 }
38
39
40
41 type RatchetingSchemaValidator struct {
42 schemaArgs
43 }
44
45 func NewRatchetingSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, options ...validate.Option) *RatchetingSchemaValidator {
46 return &RatchetingSchemaValidator{
47 schemaArgs: schemaArgs{
48 schema: schema,
49 root: rootSchema,
50 path: root,
51 knownFormats: formats,
52 options: options,
53 },
54 }
55 }
56
57 func (r *RatchetingSchemaValidator) Validate(new interface{}, options ...ValidationOption) *validate.Result {
58 sv := validate.NewSchemaValidator(r.schema, r.root, r.path, r.knownFormats, r.options...)
59 return sv.Validate(new)
60 }
61
62 func (r *RatchetingSchemaValidator) ValidateUpdate(new, old interface{}, options ...ValidationOption) *validate.Result {
63 opts := NewValidationOptions(options...)
64
65 if !opts.Ratcheting {
66 sv := validate.NewSchemaValidator(r.schema, r.root, r.path, r.knownFormats, r.options...)
67 return sv.Validate(new)
68 }
69
70 correlation := opts.CorrelatedObject
71 if correlation == nil {
72 correlation = common.NewCorrelatedObject(new, old, &celopenapi.Schema{Schema: r.schema})
73 }
74
75 return newRatchetingValueValidator(
76 correlation,
77 r.schemaArgs,
78 ).Validate(new)
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 type ratchetingValueValidator struct {
95
96
97 schemaArgs
98 correlation *common.CorrelatedObject
99 }
100
101 func newRatchetingValueValidator(correlation *common.CorrelatedObject, args schemaArgs) *ratchetingValueValidator {
102 return &ratchetingValueValidator{
103 schemaArgs: args,
104 correlation: correlation,
105 }
106 }
107
108
109
110 func (r *ratchetingValueValidator) getValidateOption() validate.Option {
111 return func(svo *validate.SchemaValidatorOptions) {
112 svo.NewValidatorForField = r.SubPropertyValidator
113 svo.NewValidatorForIndex = r.SubIndexValidator
114 }
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 func (r *ratchetingValueValidator) Validate(new interface{}) *validate.Result {
137 opts := append([]validate.Option{
138 r.getValidateOption(),
139 }, r.options...)
140
141 s := validate.NewSchemaValidator(r.schema, r.root, r.path, r.knownFormats, opts...)
142
143 res := s.Validate(r.correlation.Value)
144
145 if res.IsValid() {
146 return res
147 }
148
149
150 if r.correlation.CachedDeepEqual() {
151 newRes := &validate.Result{}
152 newRes.MergeAsWarnings(res)
153 return newRes
154 }
155
156 return res
157 }
158
159
160
161
162
163
164
165
166 func (r *ratchetingValueValidator) SubPropertyValidator(field string, schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, options ...validate.Option) validate.ValueValidator {
167 childNode := r.correlation.Key(field)
168 if childNode == nil || (r.path == "" && isTypeMetaField(field)) {
169
170
171
172
173
174
175 return validate.NewSchemaValidator(schema, rootSchema, root, formats, options...)
176 }
177
178 return newRatchetingValueValidator(childNode, schemaArgs{
179 schema: schema,
180 root: rootSchema,
181 path: root,
182 knownFormats: formats,
183 options: options,
184 })
185 }
186
187
188
189
190
191
192
193
194 func (r *ratchetingValueValidator) SubIndexValidator(index int, schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, options ...validate.Option) validate.ValueValidator {
195 childNode := r.correlation.Index(index)
196 if childNode == nil {
197 return validate.NewSchemaValidator(schema, rootSchema, root, formats, options...)
198 }
199
200 return newRatchetingValueValidator(childNode, schemaArgs{
201 schema: schema,
202 root: rootSchema,
203 path: root,
204 knownFormats: formats,
205 options: options,
206 })
207 }
208
209 var _ validate.ValueValidator = (&ratchetingValueValidator{})
210
211 func (r ratchetingValueValidator) SetPath(path string) {
212
213
214 }
215
216 func (r ratchetingValueValidator) Applies(source interface{}, valueKind reflect.Kind) bool {
217 return true
218 }
219
220 func isTypeMetaField(path string) bool {
221 return path == "kind" || path == "apiVersion"
222 }
223
View as plain text