@@ -16,15 +16,13 @@ package config
16
16
17
17
import (
18
18
"bytes"
19
- "context"
20
19
"encoding/json"
21
20
"errors"
22
21
"fmt"
23
22
"io"
24
23
"strings"
25
24
"text/template"
26
25
27
- jptr "github.com/qri-io/jsonpointer"
28
26
"github.com/qri-io/jsonschema"
29
27
"github.com/thoas/go-funk"
30
28
corev1 "k8s.io/api/core/v1"
@@ -74,11 +72,10 @@ type SchemaCheck struct {
74
72
SchemaTarget TargetKind `yaml:"schemaTarget" json:"schemaTarget"`
75
73
Schema map [string ]interface {} `yaml:"schema" json:"schema"`
76
74
SchemaString string `yaml:"schemaString" json:"schemaString"`
77
- JSONSchema string `yaml:"jsonSchema" json:"jsonSchema"`
78
- Validator * jsonschema.Schema `yaml:"-" json:"-"`
75
+ Validator jsonschema.RootSchema `yaml:"-" json:"-"`
79
76
AdditionalSchemas map [string ]map [string ]interface {} `yaml:"additionalSchemas" json:"additionalSchemas"`
80
77
AdditionalSchemaStrings map [string ]string `yaml:"additionalSchemaStrings" json:"additionalSchemaStrings"`
81
- AdditionalValidators map [string ]* jsonschema.Schema `yaml:"-" json:"-"`
78
+ AdditionalValidators map [string ]jsonschema.RootSchema `yaml:"-" json:"-"`
82
79
Mutations []Mutation `yaml:"mutations" json:"mutations"`
83
80
}
84
81
@@ -112,114 +109,59 @@ func ParseCheck(id string, rawBytes []byte) (SchemaCheck, error) {
112
109
}
113
110
114
111
func init () {
115
- jsonschema .RegisterKeyword ("resourceMinimum" , newResourceMinimum )
116
- jsonschema .RegisterKeyword ("resourceMaximum" , newResourceMaximum )
112
+ jsonschema .RegisterValidator ("resourceMinimum" , newResourceMinimum )
113
+ jsonschema .RegisterValidator ("resourceMaximum" , newResourceMaximum )
117
114
}
118
115
119
116
type includeExcludeList struct {
120
117
Include []string `yaml:"include"`
121
118
Exclude []string `yaml:"exclude"`
122
119
}
123
120
124
- func newResourceMinimum () jsonschema.Keyword {
121
+ func newResourceMinimum () jsonschema.Validator {
125
122
return new (resourceMinimum )
126
123
}
127
124
128
- func newResourceMaximum () jsonschema.Keyword {
125
+ func newResourceMaximum () jsonschema.Validator {
129
126
return new (resourceMaximum )
130
127
}
131
128
132
- // ValidateKeyword checks that a specified quanitity is not less than the minimum
133
- func (min resourceMinimum ) ValidateKeyword (ctx context.Context , currentState * jsonschema.ValidationState , data interface {}) {
134
- path := ""
135
- if currentState .InstanceLocation != nil {
136
- path = currentState .InstanceLocation .String ()
137
- }
129
+ // Validate checks that a specified quanitity is not less than the minimum
130
+ func (min resourceMinimum ) Validate (path string , data interface {}, errs * []jsonschema.ValError ) {
138
131
err := validateRange (path , string (min ), data , true )
139
132
if err != nil {
140
- for _ , e := range * err {
141
- currentState .AddError (e .InvalidValue , e .Message )
142
- }
143
- }
144
- }
145
-
146
- // Register implements jsonschema.Keyword
147
- func (min resourceMinimum ) Register (uri string , registry * jsonschema.SchemaRegistry ) {}
148
-
149
- // Resolve implements jsonschema.Keyword
150
- func (min resourceMinimum ) Resolve (pointer jptr.Pointer , uri string ) * jsonschema.Schema {
151
- return nil
152
- }
153
-
154
- // UnmarshalJSON implements json.Unmarshaler
155
- func (min * resourceMinimum ) UnmarshalJSON (data []byte ) error {
156
- var s string
157
- if err := json .Unmarshal (data , & s ); err != nil {
158
- return err
133
+ * errs = append (* errs , * err ... )
159
134
}
160
- * min = resourceMinimum (s )
161
- return nil
162
135
}
163
136
164
- // ValidateKeyword checks that a specified quanitity is not greater than the maximum
165
- func (max resourceMaximum ) ValidateKeyword (ctx context.Context , currentState * jsonschema.ValidationState , data interface {}) {
166
- path := ""
167
- if currentState .InstanceLocation != nil {
168
- path = currentState .InstanceLocation .String ()
169
- }
137
+ // Validate checks that a specified quanitity is not greater than the maximum
138
+ func (max resourceMaximum ) Validate (path string , data interface {}, errs * []jsonschema.ValError ) {
170
139
err := validateRange (path , string (max ), data , false )
171
140
if err != nil {
172
- for _ , e := range * err {
173
- currentState .AddError (e .InvalidValue , e .Message )
174
- }
141
+ * errs = append (* errs , * err ... )
175
142
}
176
143
}
177
144
178
- // Register implements jsonschema.Keyword
179
- func (max resourceMaximum ) Register (uri string , registry * jsonschema.SchemaRegistry ) {}
180
-
181
- // Resolve implements jsonschema.Keyword
182
- func (max resourceMaximum ) Resolve (pointer jptr.Pointer , uri string ) * jsonschema.Schema {
183
- return nil
184
- }
185
-
186
- // UnmarshalJSON implements json.Unmarshaler
187
- func (max * resourceMaximum ) UnmarshalJSON (data []byte ) error {
188
- var s string
189
- if err := json .Unmarshal (data , & s ); err != nil {
190
- return err
191
- }
192
- * max = resourceMaximum (s )
193
- return nil
194
- }
195
-
196
- // ValError is a custom type to maintain compatibility with the old API
197
- type ValError struct {
198
- PropertyPath string
199
- InvalidValue interface {}
200
- Message string
201
- }
202
-
203
- func parseQuantity (i interface {}) (resource.Quantity , * []ValError ) {
145
+ func parseQuantity (i interface {}) (resource.Quantity , * []jsonschema.ValError ) {
204
146
if resNum , ok := i .(float64 ); ok {
205
147
i = fmt .Sprintf ("%f" , resNum )
206
148
}
207
149
resStr , ok := i .(string )
208
150
if ! ok {
209
- return resource.Quantity {}, & []ValError {
151
+ return resource.Quantity {}, & []jsonschema. ValError {
210
152
{Message : fmt .Sprintf ("Resource quantity %v is not a string" , i )},
211
153
}
212
154
}
213
155
q , err := resource .ParseQuantity (resStr )
214
156
if err != nil {
215
- return resource.Quantity {}, & []ValError {
157
+ return resource.Quantity {}, & []jsonschema. ValError {
216
158
{Message : fmt .Sprintf ("Could not parse resource quantity: %s" , resStr )},
217
159
}
218
160
}
219
161
return q , nil
220
162
}
221
163
222
- func validateRange (path string , limit interface {}, data interface {}, isMinimum bool ) * []ValError {
164
+ func validateRange (path string , limit interface {}, data interface {}, isMinimum bool ) * []jsonschema. ValError {
223
165
limitQuantity , err := parseQuantity (limit )
224
166
if err != nil {
225
167
return err
@@ -228,31 +170,17 @@ func validateRange(path string, limit interface{}, data interface{}, isMinimum b
228
170
if err != nil {
229
171
return err
230
172
}
231
-
173
+ cmp := limitQuantity . Cmp ( actualQuantity )
232
174
if isMinimum {
233
- // For minimum, the actual quantity should be >= limit
234
- // If actual < limit, then it's an error
235
- // actualQuantity.Cmp(limitQuantity) returns -1 if actual < limit
236
- if actualQuantity .Cmp (limitQuantity ) == - 1 {
237
- return & []ValError {
238
- {
239
- PropertyPath : path ,
240
- InvalidValue : data ,
241
- Message : fmt .Sprintf ("%s quantity %v is less than minimum %v" , path , actualQuantity , limitQuantity ),
242
- },
175
+ if cmp == 1 {
176
+ return & []jsonschema.ValError {
177
+ {Message : fmt .Sprintf ("%s quantity %v is > %v" , path , actualQuantity , limitQuantity )},
243
178
}
244
179
}
245
180
} else {
246
- // For maximum, the actual quantity should be <= limit
247
- // If actual > limit, then it's an error
248
- // actualQuantity.Cmp(limitQuantity) returns 1 if actual > limit
249
- if actualQuantity .Cmp (limitQuantity ) == 1 {
250
- return & []ValError {
251
- {
252
- PropertyPath : path ,
253
- InvalidValue : data ,
254
- Message : fmt .Sprintf ("%s quantity %v is greater than maximum %v" , path , actualQuantity , limitQuantity ),
255
- },
181
+ if cmp == - 1 {
182
+ return & []jsonschema.ValError {
183
+ {Message : fmt .Sprintf ("%s quantity %v is < %v" , path , actualQuantity , limitQuantity )},
256
184
}
257
185
}
258
186
}
@@ -262,9 +190,7 @@ func validateRange(path string, limit interface{}, data interface{}, isMinimum b
262
190
// Initialize sets up the schema
263
191
func (check * SchemaCheck ) Initialize (id string ) error {
264
192
check .ID = id
265
- if check .JSONSchema != "" {
266
- check .SchemaString = check .JSONSchema
267
- } else if check .SchemaString == "" {
193
+ if check .SchemaString == "" {
268
194
jsonBytes , err := json .Marshal (check .Schema )
269
195
if err != nil {
270
196
return err
@@ -325,74 +251,50 @@ func (check SchemaCheck) TemplateForResource(res interface{}) (*SchemaCheck, err
325
251
}
326
252
}
327
253
328
- newCheck .AdditionalValidators = map [string ]* jsonschema.Schema {}
254
+ newCheck .AdditionalValidators = map [string ]jsonschema.RootSchema {}
329
255
for kind , schemaStr := range newCheck .AdditionalSchemaStrings {
330
- var schemaMap map [string ]interface {}
331
- err := UnmarshalYAMLOrJSON ([]byte (schemaStr ), & schemaMap )
332
- if err != nil {
333
- return nil , err
334
- }
335
- jsonBytes , err := json .Marshal (schemaMap )
256
+ val := jsonschema.RootSchema {}
257
+ err := UnmarshalYAMLOrJSON ([]byte (schemaStr ), & val )
336
258
if err != nil {
337
259
return nil , err
338
260
}
339
- val := jsonschema .Must (string (jsonBytes ))
340
261
newCheck .AdditionalValidators [kind ] = val
341
262
}
342
- if newCheck .SchemaString != "" {
343
- var schemaMap map [string ]interface {}
344
- err := UnmarshalYAMLOrJSON ([]byte (newCheck .SchemaString ), & schemaMap )
345
- if err != nil {
346
- return nil , err
347
- }
348
- jsonBytes , err := json .Marshal (schemaMap )
349
- if err != nil {
350
- return nil , err
351
- }
352
-
353
- // Custom keywords are now registered globally in init()
354
-
355
-
356
- newCheck .Validator = jsonschema .Must (string (jsonBytes ))
263
+ err := UnmarshalYAMLOrJSON ([]byte (newCheck .SchemaString ), & newCheck .Validator )
264
+ if err != nil {
265
+ return nil , err
357
266
}
358
- return & newCheck , nil
267
+ return & newCheck , err
359
268
}
360
269
361
270
// CheckPodSpec checks a pod spec against the schema
362
- func (check SchemaCheck ) CheckPodSpec (pod * corev1.PodSpec ) (bool , []jsonschema.KeyError , error ) {
271
+ func (check SchemaCheck ) CheckPodSpec (pod * corev1.PodSpec ) (bool , []jsonschema.ValError , error ) {
363
272
return check .CheckObject (pod )
364
273
}
365
274
366
275
// CheckPodTemplate checks a pod template against the schema
367
- func (check SchemaCheck ) CheckPodTemplate (podTemplate interface {}) (bool , []jsonschema.KeyError , error ) {
276
+ func (check SchemaCheck ) CheckPodTemplate (podTemplate interface {}) (bool , []jsonschema.ValError , error ) {
368
277
return check .CheckObject (podTemplate )
369
278
}
370
279
371
280
// CheckController checks a controler's spec against the schema
372
- func (check SchemaCheck ) CheckController (bytes []byte ) (bool , []jsonschema.KeyError , error ) {
373
- if check .Validator == nil {
374
- return true , nil , nil
375
- }
376
- errs , err := check .Validator .ValidateBytes (context .Background (), bytes )
281
+ func (check SchemaCheck ) CheckController (bytes []byte ) (bool , []jsonschema.ValError , error ) {
282
+ errs , err := check .Validator .ValidateBytes (bytes )
377
283
return len (errs ) == 0 , errs , err
378
284
}
379
285
380
286
// CheckContainer checks a container spec against the schema
381
- func (check SchemaCheck ) CheckContainer (container * corev1.Container ) (bool , []jsonschema.KeyError , error ) {
287
+ func (check SchemaCheck ) CheckContainer (container * corev1.Container ) (bool , []jsonschema.ValError , error ) {
382
288
return check .CheckObject (container )
383
289
}
384
290
385
291
// CheckObject checks arbitrary data against the schema
386
- func (check SchemaCheck ) CheckObject (obj interface {}) (bool , []jsonschema.KeyError , error ) {
292
+ func (check SchemaCheck ) CheckObject (obj interface {}) (bool , []jsonschema.ValError , error ) {
387
293
bytes , err := json .Marshal (obj )
388
294
if err != nil {
389
295
return false , nil , err
390
296
}
391
- if check .Validator == nil {
392
- return true , nil , nil
393
- }
394
-
395
- errs , err := check .Validator .ValidateBytes (context .Background (), bytes )
297
+ errs , err := check .Validator .ValidateBytes (bytes )
396
298
return len (errs ) == 0 , errs , err
397
299
}
398
300
@@ -407,7 +309,7 @@ func (check SchemaCheck) CheckAdditionalObjects(groupkind string, objects []inte
407
309
if err != nil {
408
310
return false , err
409
311
}
410
- errs , err := val .ValidateBytes (context . Background (), bytes )
312
+ errs , err := val .ValidateBytes (bytes )
411
313
if err != nil {
412
314
return false , err
413
315
}
@@ -465,4 +367,4 @@ func (check SchemaCheck) IsActionable(target TargetKind, kind string, isInit boo
465
367
}
466
368
}
467
369
return true
468
- }
370
+ }
0 commit comments