diff --git a/pkg/runtime/helper.go b/pkg/runtime/helper.go index f3f1805493f..b087d79464c 100644 --- a/pkg/runtime/helper.go +++ b/pkg/runtime/helper.go @@ -41,10 +41,14 @@ func GetItemsPtr(list Object) (interface{}, error) { if !items.IsValid() { return nil, fmt.Errorf("no Items field in %#v", list) } - if items.Kind() != reflect.Slice { - return nil, fmt.Errorf("Items field is not a slice") + switch items.Kind() { + case reflect.Interface, reflect.Ptr: + return items.Interface(), nil + case reflect.Slice: + return items.Addr().Interface(), nil + default: + return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind()) } - return items.Addr().Interface(), nil } // ExtractList returns obj's Items element as an array of runtime.Objects. @@ -61,11 +65,16 @@ func ExtractList(obj Object) ([]Object, error) { list := make([]Object, items.Len()) for i := range list { raw := items.Index(i) - item, ok := raw.Addr().Interface().(Object) - if !ok { - return nil, fmt.Errorf("item[%v]: Expected object, got %#v", i, raw.Interface()) + var found bool + switch raw.Kind() { + case reflect.Interface, reflect.Ptr: + list[i], found = raw.Interface().(Object) + default: + list[i], found = raw.Addr().Interface().(Object) + } + if !found { + return nil, fmt.Errorf("item[%v]: Expected object, got %#v(%s)", i, raw.Interface(), raw.Kind()) } - list[i] = item } return list, nil } diff --git a/pkg/runtime/helper_test.go b/pkg/runtime/helper_test.go index f2c18de7db4..f194b133af9 100644 --- a/pkg/runtime/helper_test.go +++ b/pkg/runtime/helper_test.go @@ -63,6 +63,74 @@ func TestExtractList(t *testing.T) { } } +func TestExtractListGeneric(t *testing.T) { + pl := &api.List{ + Items: []runtime.Object{ + &api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, + &api.Service{ObjectMeta: api.ObjectMeta{Name: "2"}}, + }, + } + list, err := runtime.ExtractList(pl) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if e, a := len(list), len(pl.Items); e != a { + t.Fatalf("Expected %v, got %v", e, a) + } + if obj, ok := list[0].(*api.Pod); !ok { + t.Fatalf("Expected list[0] to be *api.Pod, it is %#v", obj) + } + if obj, ok := list[1].(*api.Service); !ok { + t.Fatalf("Expected list[1] to be *api.Service, it is %#v", obj) + } +} + +type fakePtrInterfaceList struct { + Items []*runtime.Object +} + +func (f fakePtrInterfaceList) IsAnAPIObject() {} + +func TestExtractListOfInterfacePtrs(t *testing.T) { + pl := &fakePtrInterfaceList{ + Items: []*runtime.Object{}, + } + list, err := runtime.ExtractList(pl) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if len(list) > 0 { + t.Fatalf("Expected empty list, got %#v", list) + } +} + +type fakePtrValueList struct { + Items []*api.Pod +} + +func (f fakePtrValueList) IsAnAPIObject() {} + +func TestExtractListOfValuePtrs(t *testing.T) { + pl := &fakePtrValueList{ + Items: []*api.Pod{ + {ObjectMeta: api.ObjectMeta{Name: "1"}}, + {ObjectMeta: api.ObjectMeta{Name: "2"}}, + }, + } + list, err := runtime.ExtractList(pl) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if e, a := len(list), len(pl.Items); e != a { + t.Fatalf("Expected %v, got %v", e, a) + } + for i := range list { + if obj, ok := list[i].(*api.Pod); !ok { + t.Fatalf("Expected list[%d] to be *api.Pod, it is %#v", i, obj) + } + } +} + func TestSetList(t *testing.T) { pl := &api.PodList{} list := []runtime.Object{