Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / apis / meta / v1 / unstructured / helpers.go
1 /*
2 Copyright 2015 The Kubernetes Authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package unstructured
18
19 import (
20         gojson "encoding/json"
21         "fmt"
22         "io"
23         "strings"
24
25         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26         "k8s.io/apimachinery/pkg/runtime"
27         "k8s.io/apimachinery/pkg/runtime/schema"
28         "k8s.io/apimachinery/pkg/types"
29         "k8s.io/apimachinery/pkg/util/json"
30 )
31
32 // NestedFieldCopy returns a deep copy of the value of a nested field.
33 // Returns false if the value is missing.
34 // No error is returned for a nil field.
35 func NestedFieldCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
36         val, found, err := NestedFieldNoCopy(obj, fields...)
37         if !found || err != nil {
38                 return nil, found, err
39         }
40         return runtime.DeepCopyJSONValue(val), true, nil
41 }
42
43 // NestedFieldNoCopy returns a reference to a nested field.
44 // Returns false if value is not found and an error if unable
45 // to traverse obj.
46 func NestedFieldNoCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
47         var val interface{} = obj
48
49         for i, field := range fields {
50                 if m, ok := val.(map[string]interface{}); ok {
51                         val, ok = m[field]
52                         if !ok {
53                                 return nil, false, nil
54                         }
55                 } else {
56                         return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected map[string]interface{}", jsonPath(fields[:i+1]), val, val)
57                 }
58         }
59         return val, true, nil
60 }
61
62 // NestedString returns the string value of a nested field.
63 // Returns false if value is not found and an error if not a string.
64 func NestedString(obj map[string]interface{}, fields ...string) (string, bool, error) {
65         val, found, err := NestedFieldNoCopy(obj, fields...)
66         if !found || err != nil {
67                 return "", found, err
68         }
69         s, ok := val.(string)
70         if !ok {
71                 return "", false, fmt.Errorf("%v accessor error: %v is of the type %T, expected string", jsonPath(fields), val, val)
72         }
73         return s, true, nil
74 }
75
76 // NestedBool returns the bool value of a nested field.
77 // Returns false if value is not found and an error if not a bool.
78 func NestedBool(obj map[string]interface{}, fields ...string) (bool, bool, error) {
79         val, found, err := NestedFieldNoCopy(obj, fields...)
80         if !found || err != nil {
81                 return false, found, err
82         }
83         b, ok := val.(bool)
84         if !ok {
85                 return false, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected bool", jsonPath(fields), val, val)
86         }
87         return b, true, nil
88 }
89
90 // NestedFloat64 returns the float64 value of a nested field.
91 // Returns false if value is not found and an error if not a float64.
92 func NestedFloat64(obj map[string]interface{}, fields ...string) (float64, bool, error) {
93         val, found, err := NestedFieldNoCopy(obj, fields...)
94         if !found || err != nil {
95                 return 0, found, err
96         }
97         f, ok := val.(float64)
98         if !ok {
99                 return 0, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected float64", jsonPath(fields), val, val)
100         }
101         return f, true, nil
102 }
103
104 // NestedInt64 returns the int64 value of a nested field.
105 // Returns false if value is not found and an error if not an int64.
106 func NestedInt64(obj map[string]interface{}, fields ...string) (int64, bool, error) {
107         val, found, err := NestedFieldNoCopy(obj, fields...)
108         if !found || err != nil {
109                 return 0, found, err
110         }
111         i, ok := val.(int64)
112         if !ok {
113                 return 0, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected int64", jsonPath(fields), val, val)
114         }
115         return i, true, nil
116 }
117
118 // NestedStringSlice returns a copy of []string value of a nested field.
119 // Returns false if value is not found and an error if not a []interface{} or contains non-string items in the slice.
120 func NestedStringSlice(obj map[string]interface{}, fields ...string) ([]string, bool, error) {
121         val, found, err := NestedFieldNoCopy(obj, fields...)
122         if !found || err != nil {
123                 return nil, found, err
124         }
125         m, ok := val.([]interface{})
126         if !ok {
127                 return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected []interface{}", jsonPath(fields), val, val)
128         }
129         strSlice := make([]string, 0, len(m))
130         for _, v := range m {
131                 if str, ok := v.(string); ok {
132                         strSlice = append(strSlice, str)
133                 } else {
134                         return nil, false, fmt.Errorf("%v accessor error: contains non-string key in the slice: %v is of the type %T, expected string", jsonPath(fields), v, v)
135                 }
136         }
137         return strSlice, true, nil
138 }
139
140 // NestedSlice returns a deep copy of []interface{} value of a nested field.
141 // Returns false if value is not found and an error if not a []interface{}.
142 func NestedSlice(obj map[string]interface{}, fields ...string) ([]interface{}, bool, error) {
143         val, found, err := NestedFieldNoCopy(obj, fields...)
144         if !found || err != nil {
145                 return nil, found, err
146         }
147         _, ok := val.([]interface{})
148         if !ok {
149                 return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected []interface{}", jsonPath(fields), val, val)
150         }
151         return runtime.DeepCopyJSONValue(val).([]interface{}), true, nil
152 }
153
154 // NestedStringMap returns a copy of map[string]string value of a nested field.
155 // Returns false if value is not found and an error if not a map[string]interface{} or contains non-string values in the map.
156 func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]string, bool, error) {
157         m, found, err := nestedMapNoCopy(obj, fields...)
158         if !found || err != nil {
159                 return nil, found, err
160         }
161         strMap := make(map[string]string, len(m))
162         for k, v := range m {
163                 if str, ok := v.(string); ok {
164                         strMap[k] = str
165                 } else {
166                         return nil, false, fmt.Errorf("%v accessor error: contains non-string key in the map: %v is of the type %T, expected string", jsonPath(fields), v, v)
167                 }
168         }
169         return strMap, true, nil
170 }
171
172 // NestedMap returns a deep copy of map[string]interface{} value of a nested field.
173 // Returns false if value is not found and an error if not a map[string]interface{}.
174 func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) {
175         m, found, err := nestedMapNoCopy(obj, fields...)
176         if !found || err != nil {
177                 return nil, found, err
178         }
179         return runtime.DeepCopyJSON(m), true, nil
180 }
181
182 // nestedMapNoCopy returns a map[string]interface{} value of a nested field.
183 // Returns false if value is not found and an error if not a map[string]interface{}.
184 func nestedMapNoCopy(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) {
185         val, found, err := NestedFieldNoCopy(obj, fields...)
186         if !found || err != nil {
187                 return nil, found, err
188         }
189         m, ok := val.(map[string]interface{})
190         if !ok {
191                 return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected map[string]interface{}", jsonPath(fields), val, val)
192         }
193         return m, true, nil
194 }
195
196 // SetNestedField sets the value of a nested field to a deep copy of the value provided.
197 // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
198 func SetNestedField(obj map[string]interface{}, value interface{}, fields ...string) error {
199         return setNestedFieldNoCopy(obj, runtime.DeepCopyJSONValue(value), fields...)
200 }
201
202 func setNestedFieldNoCopy(obj map[string]interface{}, value interface{}, fields ...string) error {
203         m := obj
204
205         for i, field := range fields[:len(fields)-1] {
206                 if val, ok := m[field]; ok {
207                         if valMap, ok := val.(map[string]interface{}); ok {
208                                 m = valMap
209                         } else {
210                                 return fmt.Errorf("value cannot be set because %v is not a map[string]interface{}", jsonPath(fields[:i+1]))
211                         }
212                 } else {
213                         newVal := make(map[string]interface{})
214                         m[field] = newVal
215                         m = newVal
216                 }
217         }
218         m[fields[len(fields)-1]] = value
219         return nil
220 }
221
222 // SetNestedStringSlice sets the string slice value of a nested field.
223 // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
224 func SetNestedStringSlice(obj map[string]interface{}, value []string, fields ...string) error {
225         m := make([]interface{}, 0, len(value)) // convert []string into []interface{}
226         for _, v := range value {
227                 m = append(m, v)
228         }
229         return setNestedFieldNoCopy(obj, m, fields...)
230 }
231
232 // SetNestedSlice sets the slice value of a nested field.
233 // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
234 func SetNestedSlice(obj map[string]interface{}, value []interface{}, fields ...string) error {
235         return SetNestedField(obj, value, fields...)
236 }
237
238 // SetNestedStringMap sets the map[string]string value of a nested field.
239 // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
240 func SetNestedStringMap(obj map[string]interface{}, value map[string]string, fields ...string) error {
241         m := make(map[string]interface{}, len(value)) // convert map[string]string into map[string]interface{}
242         for k, v := range value {
243                 m[k] = v
244         }
245         return setNestedFieldNoCopy(obj, m, fields...)
246 }
247
248 // SetNestedMap sets the map[string]interface{} value of a nested field.
249 // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
250 func SetNestedMap(obj map[string]interface{}, value map[string]interface{}, fields ...string) error {
251         return SetNestedField(obj, value, fields...)
252 }
253
254 // RemoveNestedField removes the nested field from the obj.
255 func RemoveNestedField(obj map[string]interface{}, fields ...string) {
256         m := obj
257         for _, field := range fields[:len(fields)-1] {
258                 if x, ok := m[field].(map[string]interface{}); ok {
259                         m = x
260                 } else {
261                         return
262                 }
263         }
264         delete(m, fields[len(fields)-1])
265 }
266
267 func getNestedString(obj map[string]interface{}, fields ...string) string {
268         val, found, err := NestedString(obj, fields...)
269         if !found || err != nil {
270                 return ""
271         }
272         return val
273 }
274
275 func jsonPath(fields []string) string {
276         return "." + strings.Join(fields, ".")
277 }
278
279 func extractOwnerReference(v map[string]interface{}) metav1.OwnerReference {
280         // though this field is a *bool, but when decoded from JSON, it's
281         // unmarshalled as bool.
282         var controllerPtr *bool
283         if controller, found, err := NestedBool(v, "controller"); err == nil && found {
284                 controllerPtr = &controller
285         }
286         var blockOwnerDeletionPtr *bool
287         if blockOwnerDeletion, found, err := NestedBool(v, "blockOwnerDeletion"); err == nil && found {
288                 blockOwnerDeletionPtr = &blockOwnerDeletion
289         }
290         return metav1.OwnerReference{
291                 Kind:               getNestedString(v, "kind"),
292                 Name:               getNestedString(v, "name"),
293                 APIVersion:         getNestedString(v, "apiVersion"),
294                 UID:                types.UID(getNestedString(v, "uid")),
295                 Controller:         controllerPtr,
296                 BlockOwnerDeletion: blockOwnerDeletionPtr,
297         }
298 }
299
300 // UnstructuredJSONScheme is capable of converting JSON data into the Unstructured
301 // type, which can be used for generic access to objects without a predefined scheme.
302 // TODO: move into serializer/json.
303 var UnstructuredJSONScheme runtime.Codec = unstructuredJSONScheme{}
304
305 type unstructuredJSONScheme struct{}
306
307 func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
308         var err error
309         if obj != nil {
310                 err = s.decodeInto(data, obj)
311         } else {
312                 obj, err = s.decode(data)
313         }
314
315         if err != nil {
316                 return nil, nil, err
317         }
318
319         gvk := obj.GetObjectKind().GroupVersionKind()
320         if len(gvk.Kind) == 0 {
321                 return nil, &gvk, runtime.NewMissingKindErr(string(data))
322         }
323
324         return obj, &gvk, nil
325 }
326
327 func (unstructuredJSONScheme) Encode(obj runtime.Object, w io.Writer) error {
328         switch t := obj.(type) {
329         case *Unstructured:
330                 return json.NewEncoder(w).Encode(t.Object)
331         case *UnstructuredList:
332                 items := make([]interface{}, 0, len(t.Items))
333                 for _, i := range t.Items {
334                         items = append(items, i.Object)
335                 }
336                 listObj := make(map[string]interface{}, len(t.Object)+1)
337                 for k, v := range t.Object { // Make a shallow copy
338                         listObj[k] = v
339                 }
340                 listObj["items"] = items
341                 return json.NewEncoder(w).Encode(listObj)
342         case *runtime.Unknown:
343                 // TODO: Unstructured needs to deal with ContentType.
344                 _, err := w.Write(t.Raw)
345                 return err
346         default:
347                 return json.NewEncoder(w).Encode(t)
348         }
349 }
350
351 func (s unstructuredJSONScheme) decode(data []byte) (runtime.Object, error) {
352         type detector struct {
353                 Items gojson.RawMessage
354         }
355         var det detector
356         if err := json.Unmarshal(data, &det); err != nil {
357                 return nil, err
358         }
359
360         if det.Items != nil {
361                 list := &UnstructuredList{}
362                 err := s.decodeToList(data, list)
363                 return list, err
364         }
365
366         // No Items field, so it wasn't a list.
367         unstruct := &Unstructured{}
368         err := s.decodeToUnstructured(data, unstruct)
369         return unstruct, err
370 }
371
372 func (s unstructuredJSONScheme) decodeInto(data []byte, obj runtime.Object) error {
373         switch x := obj.(type) {
374         case *Unstructured:
375                 return s.decodeToUnstructured(data, x)
376         case *UnstructuredList:
377                 return s.decodeToList(data, x)
378         case *runtime.VersionedObjects:
379                 o, err := s.decode(data)
380                 if err == nil {
381                         x.Objects = []runtime.Object{o}
382                 }
383                 return err
384         default:
385                 return json.Unmarshal(data, x)
386         }
387 }
388
389 func (unstructuredJSONScheme) decodeToUnstructured(data []byte, unstruct *Unstructured) error {
390         m := make(map[string]interface{})
391         if err := json.Unmarshal(data, &m); err != nil {
392                 return err
393         }
394
395         unstruct.Object = m
396
397         return nil
398 }
399
400 func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList) error {
401         type decodeList struct {
402                 Items []gojson.RawMessage
403         }
404
405         var dList decodeList
406         if err := json.Unmarshal(data, &dList); err != nil {
407                 return err
408         }
409
410         if err := json.Unmarshal(data, &list.Object); err != nil {
411                 return err
412         }
413
414         // For typed lists, e.g., a PodList, API server doesn't set each item's
415         // APIVersion and Kind. We need to set it.
416         listAPIVersion := list.GetAPIVersion()
417         listKind := list.GetKind()
418         itemKind := strings.TrimSuffix(listKind, "List")
419
420         delete(list.Object, "items")
421         list.Items = make([]Unstructured, 0, len(dList.Items))
422         for _, i := range dList.Items {
423                 unstruct := &Unstructured{}
424                 if err := s.decodeToUnstructured([]byte(i), unstruct); err != nil {
425                         return err
426                 }
427                 // This is hacky. Set the item's Kind and APIVersion to those inferred
428                 // from the List.
429                 if len(unstruct.GetKind()) == 0 && len(unstruct.GetAPIVersion()) == 0 {
430                         unstruct.SetKind(itemKind)
431                         unstruct.SetAPIVersion(listAPIVersion)
432                 }
433                 list.Items = append(list.Items, *unstruct)
434         }
435         return nil
436 }
437
438 type JSONFallbackEncoder struct {
439         runtime.Encoder
440 }
441
442 func (c JSONFallbackEncoder) Encode(obj runtime.Object, w io.Writer) error {
443         err := c.Encoder.Encode(obj, w)
444         if runtime.IsNotRegisteredError(err) {
445                 switch obj.(type) {
446                 case *Unstructured, *UnstructuredList:
447                         return UnstructuredJSONScheme.Encode(obj, w)
448                 }
449         }
450         return err
451 }