Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / api / meta / help.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 meta
18
19 import (
20         "fmt"
21         "reflect"
22
23         "k8s.io/apimachinery/pkg/conversion"
24         "k8s.io/apimachinery/pkg/runtime"
25 )
26
27 // IsListType returns true if the provided Object has a slice called Items
28 func IsListType(obj runtime.Object) bool {
29         // if we're a runtime.Unstructured, check whether this is a list.
30         // TODO: refactor GetItemsPtr to use an interface that returns []runtime.Object
31         if unstructured, ok := obj.(runtime.Unstructured); ok {
32                 return unstructured.IsList()
33         }
34
35         _, err := GetItemsPtr(obj)
36         return err == nil
37 }
38
39 // GetItemsPtr returns a pointer to the list object's Items member.
40 // If 'list' doesn't have an Items member, it's not really a list type
41 // and an error will be returned.
42 // This function will either return a pointer to a slice, or an error, but not both.
43 func GetItemsPtr(list runtime.Object) (interface{}, error) {
44         v, err := conversion.EnforcePtr(list)
45         if err != nil {
46                 return nil, err
47         }
48
49         items := v.FieldByName("Items")
50         if !items.IsValid() {
51                 return nil, fmt.Errorf("no Items field in %#v", list)
52         }
53         switch items.Kind() {
54         case reflect.Interface, reflect.Ptr:
55                 target := reflect.TypeOf(items.Interface()).Elem()
56                 if target.Kind() != reflect.Slice {
57                         return nil, fmt.Errorf("items: Expected slice, got %s", target.Kind())
58                 }
59                 return items.Interface(), nil
60         case reflect.Slice:
61                 return items.Addr().Interface(), nil
62         default:
63                 return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind())
64         }
65 }
66
67 // EachListItem invokes fn on each runtime.Object in the list. Any error immediately terminates
68 // the loop.
69 func EachListItem(obj runtime.Object, fn func(runtime.Object) error) error {
70         if unstructured, ok := obj.(runtime.Unstructured); ok {
71                 return unstructured.EachListItem(fn)
72         }
73         // TODO: Change to an interface call?
74         itemsPtr, err := GetItemsPtr(obj)
75         if err != nil {
76                 return err
77         }
78         items, err := conversion.EnforcePtr(itemsPtr)
79         if err != nil {
80                 return err
81         }
82         len := items.Len()
83         if len == 0 {
84                 return nil
85         }
86         takeAddr := false
87         if elemType := items.Type().Elem(); elemType.Kind() != reflect.Ptr && elemType.Kind() != reflect.Interface {
88                 if !items.Index(0).CanAddr() {
89                         return fmt.Errorf("unable to take address of items in %T for EachListItem", obj)
90                 }
91                 takeAddr = true
92         }
93
94         for i := 0; i < len; i++ {
95                 raw := items.Index(i)
96                 if takeAddr {
97                         raw = raw.Addr()
98                 }
99                 switch item := raw.Interface().(type) {
100                 case *runtime.RawExtension:
101                         if err := fn(item.Object); err != nil {
102                                 return err
103                         }
104                 case runtime.Object:
105                         if err := fn(item); err != nil {
106                                 return err
107                         }
108                 default:
109                         obj, ok := item.(runtime.Object)
110                         if !ok {
111                                 return fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
112                         }
113                         if err := fn(obj); err != nil {
114                                 return err
115                         }
116                 }
117         }
118         return nil
119 }
120
121 // ExtractList returns obj's Items element as an array of runtime.Objects.
122 // Returns an error if obj is not a List type (does not have an Items member).
123 func ExtractList(obj runtime.Object) ([]runtime.Object, error) {
124         itemsPtr, err := GetItemsPtr(obj)
125         if err != nil {
126                 return nil, err
127         }
128         items, err := conversion.EnforcePtr(itemsPtr)
129         if err != nil {
130                 return nil, err
131         }
132         list := make([]runtime.Object, items.Len())
133         for i := range list {
134                 raw := items.Index(i)
135                 switch item := raw.Interface().(type) {
136                 case runtime.RawExtension:
137                         switch {
138                         case item.Object != nil:
139                                 list[i] = item.Object
140                         case item.Raw != nil:
141                                 // TODO: Set ContentEncoding and ContentType correctly.
142                                 list[i] = &runtime.Unknown{Raw: item.Raw}
143                         default:
144                                 list[i] = nil
145                         }
146                 case runtime.Object:
147                         list[i] = item
148                 default:
149                         var found bool
150                         if list[i], found = raw.Addr().Interface().(runtime.Object); !found {
151                                 return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
152                         }
153                 }
154         }
155         return list, nil
156 }
157
158 // objectSliceType is the type of a slice of Objects
159 var objectSliceType = reflect.TypeOf([]runtime.Object{})
160
161 // SetList sets the given list object's Items member have the elements given in
162 // objects.
163 // Returns an error if list is not a List type (does not have an Items member),
164 // or if any of the objects are not of the right type.
165 func SetList(list runtime.Object, objects []runtime.Object) error {
166         itemsPtr, err := GetItemsPtr(list)
167         if err != nil {
168                 return err
169         }
170         items, err := conversion.EnforcePtr(itemsPtr)
171         if err != nil {
172                 return err
173         }
174         if items.Type() == objectSliceType {
175                 items.Set(reflect.ValueOf(objects))
176                 return nil
177         }
178         slice := reflect.MakeSlice(items.Type(), len(objects), len(objects))
179         for i := range objects {
180                 dest := slice.Index(i)
181                 if dest.Type() == reflect.TypeOf(runtime.RawExtension{}) {
182                         dest = dest.FieldByName("Object")
183                 }
184
185                 // check to see if you're directly assignable
186                 if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
187                         dest.Set(reflect.ValueOf(objects[i]))
188                         continue
189                 }
190
191                 src, err := conversion.EnforcePtr(objects[i])
192                 if err != nil {
193                         return err
194                 }
195                 if src.Type().AssignableTo(dest.Type()) {
196                         dest.Set(src)
197                 } else if src.Type().ConvertibleTo(dest.Type()) {
198                         dest.Set(src.Convert(dest.Type()))
199                 } else {
200                         return fmt.Errorf("item[%d]: can't assign or convert %v into %v", i, src.Type(), dest.Type())
201                 }
202         }
203         items.Set(slice)
204         return nil
205 }