1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17 import (
18 "reflect"
19 "regexp"
20
21 "k8s.io/kube-openapi/pkg/validation/errors"
22 "k8s.io/kube-openapi/pkg/validation/spec"
23 "k8s.io/kube-openapi/pkg/validation/strfmt"
24 )
25
26 type objectValidator struct {
27 Path string
28 In string
29 MaxProperties *int64
30 MinProperties *int64
31 Required []string
32 Properties map[string]spec.Schema
33 AdditionalProperties *spec.SchemaOrBool
34 PatternProperties map[string]spec.Schema
35 Root interface{}
36 KnownFormats strfmt.Registry
37 Options SchemaValidatorOptions
38 }
39
40 func (o *objectValidator) SetPath(path string) {
41 o.Path = path
42 }
43
44 func (o *objectValidator) Applies(source interface{}, kind reflect.Kind) bool {
45
46
47
48 r := reflect.TypeOf(source) == specSchemaType && (kind == reflect.Map || kind == reflect.Struct)
49 debugLog("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind)
50 return r
51 }
52
53 func (o *objectValidator) Validate(data interface{}) *Result {
54 val := data.(map[string]interface{})
55
56 numKeys := int64(len(val))
57
58 res := new(Result)
59
60 if o.MinProperties != nil && numKeys < *o.MinProperties {
61 res.AddErrors(errors.TooFewProperties(o.Path, o.In, *o.MinProperties, numKeys))
62 }
63 if o.MaxProperties != nil && numKeys > *o.MaxProperties {
64 res.AddErrors(errors.TooManyProperties(o.Path, o.In, *o.MaxProperties, numKeys))
65 }
66
67
68 if o.AdditionalProperties != nil && !o.AdditionalProperties.Allows {
69
70 for k := range val {
71 _, regularProperty := o.Properties[k]
72 matched := false
73
74 for pk := range o.PatternProperties {
75 if matches, _ := regexp.MatchString(pk, k); matches {
76 matched = true
77 break
78 }
79 }
80
81 if !regularProperty && !matched {
82
83 res.AddErrors(errors.PropertyNotAllowed(o.Path, o.In, k))
84 }
85 }
86 } else {
87
88 for key, value := range val {
89 _, regularProperty := o.Properties[key]
90
91
92
93
94
95 matched, succeededOnce, _ := o.validatePatternProperty(key, value, res)
96
97 if !(regularProperty || matched || succeededOnce) {
98
99
100 if o.AdditionalProperties != nil && o.AdditionalProperties.Schema != nil {
101
102 res.Merge(o.Options.NewValidatorForField(key, o.AdditionalProperties.Schema, o.Root, o.Path+"."+key, o.KnownFormats, o.Options.Options()...).Validate(value))
103 } else if regularProperty && !(matched || succeededOnce) {
104
105 res.AddErrors(errors.FailedAllPatternProperties(o.Path, o.In, key))
106 }
107 }
108 }
109
110 }
111
112 createdFromDefaults := map[string]bool{}
113
114
115
116 for pName, pSchema := range o.Properties {
117 rName := pName
118 if o.Path != "" {
119 rName = o.Path + "." + pName
120 }
121
122
123 if v, ok := val[pName]; ok {
124 r := o.Options.NewValidatorForField(pName, &pSchema, o.Root, rName, o.KnownFormats, o.Options.Options()...).Validate(v)
125 res.Merge(r)
126 }
127 }
128
129
130 if len(o.Required) > 0 {
131 for _, k := range o.Required {
132 if _, ok := val[k]; !ok && !createdFromDefaults[k] {
133 res.AddErrors(errors.Required(o.Path+"."+k, o.In))
134 continue
135 }
136 }
137 }
138
139
140
141 for key, value := range val {
142 _, regularProperty := o.Properties[key]
143 matched, _ , patterns := o.validatePatternProperty(key, value, res)
144 if !regularProperty && (matched ) {
145 for _, pName := range patterns {
146 if v, ok := o.PatternProperties[pName]; ok {
147 res.Merge(o.Options.NewValidatorForField(key, &v, o.Root, o.Path+"."+key, o.KnownFormats, o.Options.Options()...).Validate(value))
148 }
149 }
150 }
151 }
152 return res
153 }
154
155
156 func (o *objectValidator) validatePatternProperty(key string, value interface{}, result *Result) (bool, bool, []string) {
157 matched := false
158 succeededOnce := false
159 var patterns []string
160
161 for k, schema := range o.PatternProperties {
162 sch := schema
163 if match, _ := regexp.MatchString(k, key); match {
164 patterns = append(patterns, k)
165 matched = true
166 validator := o.Options.NewValidatorForField(key, &sch, o.Root, o.Path+"."+key, o.KnownFormats, o.Options.Options()...)
167
168 res := validator.Validate(value)
169 result.Merge(res)
170 }
171 }
172
173
174
175
176
177
178
179 return matched, succeededOnce, patterns
180 }
181
View as plain text