2 Copyright 2015 The Kubernetes Authors.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
23 "k8s.io/apimachinery/pkg/conversion"
24 "k8s.io/apimachinery/pkg/runtime"
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()
35 _, err := GetItemsPtr(obj)
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)
49 items := v.FieldByName("Items")
51 return nil, fmt.Errorf("no Items field in %#v", list)
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())
59 return items.Interface(), nil
61 return items.Addr().Interface(), nil
63 return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind())
67 // EachListItem invokes fn on each runtime.Object in the list. Any error immediately terminates
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)
73 // TODO: Change to an interface call?
74 itemsPtr, err := GetItemsPtr(obj)
78 items, err := conversion.EnforcePtr(itemsPtr)
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)
94 for i := 0; i < len; i++ {
99 switch item := raw.Interface().(type) {
100 case *runtime.RawExtension:
101 if err := fn(item.Object); err != nil {
105 if err := fn(item); err != nil {
109 obj, ok := item.(runtime.Object)
111 return fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
113 if err := fn(obj); err != nil {
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)
128 items, err := conversion.EnforcePtr(itemsPtr)
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:
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}
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())
158 // objectSliceType is the type of a slice of Objects
159 var objectSliceType = reflect.TypeOf([]runtime.Object{})
161 // SetList sets the given list object's Items member have the elements given in
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)
170 items, err := conversion.EnforcePtr(itemsPtr)
174 if items.Type() == objectSliceType {
175 items.Set(reflect.ValueOf(objects))
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")
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]))
191 src, err := conversion.EnforcePtr(objects[i])
195 if src.Type().AssignableTo(dest.Type()) {
197 } else if src.Type().ConvertibleTo(dest.Type()) {
198 dest.Set(src.Convert(dest.Type()))
200 return fmt.Errorf("item[%d]: can't assign or convert %v into %v", i, src.Type(), dest.Type())