...
1
16
17 package validation
18
19 import (
20 "errors"
21
22 "k8s.io/apimachinery/pkg/runtime/schema"
23 utilerrors "k8s.io/apimachinery/pkg/util/errors"
24 "k8s.io/apimachinery/pkg/util/json"
25 "k8s.io/apimachinery/pkg/util/yaml"
26 "k8s.io/kube-openapi/pkg/util/proto/validation"
27 "k8s.io/kubectl/pkg/util/openapi"
28 )
29
30
31 type schemaValidation struct {
32 resourcesGetter openapi.OpenAPIResourcesGetter
33 }
34
35
36
37 func NewSchemaValidation(resourcesGetter openapi.OpenAPIResourcesGetter) Schema {
38 return &schemaValidation{
39 resourcesGetter: resourcesGetter,
40 }
41 }
42
43
44
45 func (v *schemaValidation) ValidateBytes(data []byte) error {
46 obj, err := parse(data)
47 if err != nil {
48 return err
49 }
50
51 gvk, errs := getObjectKind(obj)
52 if errs != nil {
53 return utilerrors.NewAggregate(errs)
54 }
55
56 if (gvk == schema.GroupVersionKind{Version: "v1", Kind: "List"}) {
57 return utilerrors.NewAggregate(v.validateList(obj))
58 }
59 return utilerrors.NewAggregate(v.validateResource(obj, gvk))
60 }
61
62 func (v *schemaValidation) validateList(object interface{}) []error {
63 fields, ok := object.(map[string]interface{})
64 if !ok || fields == nil {
65 return []error{errors.New("invalid object to validate")}
66 }
67
68 allErrors := []error{}
69 if _, ok := fields["items"].([]interface{}); !ok {
70 return []error{errors.New("invalid object to validate")}
71 }
72 for _, item := range fields["items"].([]interface{}) {
73 if gvk, errs := getObjectKind(item); errs != nil {
74 allErrors = append(allErrors, errs...)
75 } else {
76 allErrors = append(allErrors, v.validateResource(item, gvk)...)
77 }
78 }
79 return allErrors
80 }
81
82 func (v *schemaValidation) validateResource(obj interface{}, gvk schema.GroupVersionKind) []error {
83
84 resources, err := v.resourcesGetter.OpenAPISchema()
85 if err != nil {
86 return []error{err}
87 }
88 resource := resources.LookupResource(gvk)
89 if resource == nil {
90
91 return nil
92 }
93
94 return validation.ValidateModel(obj, resource, gvk.Kind)
95 }
96
97 func parse(data []byte) (interface{}, error) {
98 var obj interface{}
99 out, err := yaml.ToJSON(data)
100 if err != nil {
101 return nil, err
102 }
103 if err := json.Unmarshal(out, &obj); err != nil {
104 return nil, err
105 }
106 return obj, nil
107 }
108
109 func getObjectKind(object interface{}) (schema.GroupVersionKind, []error) {
110 var listErrors []error
111 fields, ok := object.(map[string]interface{})
112 if !ok || fields == nil {
113 listErrors = append(listErrors, errors.New("invalid object to validate"))
114 return schema.GroupVersionKind{}, listErrors
115 }
116
117 var group string
118 var version string
119 apiVersion := fields["apiVersion"]
120 if apiVersion == nil {
121 listErrors = append(listErrors, errors.New("apiVersion not set"))
122 } else if _, ok := apiVersion.(string); !ok {
123 listErrors = append(listErrors, errors.New("apiVersion isn't string type"))
124 } else {
125 gv, err := schema.ParseGroupVersion(apiVersion.(string))
126 if err != nil {
127 listErrors = append(listErrors, err)
128 } else {
129 group = gv.Group
130 version = gv.Version
131 }
132 }
133 kind := fields["kind"]
134 if kind == nil {
135 listErrors = append(listErrors, errors.New("kind not set"))
136 } else if _, ok := kind.(string); !ok {
137 listErrors = append(listErrors, errors.New("kind isn't string type"))
138 }
139 if listErrors != nil {
140 return schema.GroupVersionKind{}, listErrors
141 }
142
143 return schema.GroupVersionKind{Group: group, Version: version, Kind: kind.(string)}, nil
144 }
145
View as plain text