// SetList sets the given list object's Items member have the elements given in // objects. // Returns an error if list is not a List type (does not have an Items member), // or if any of the objects are not of the right type. func SetList(list runtime.Object, objects []runtime.Object) error { itemsPtr, err := GetItemsPtr(list) if err != nil { return err } items, err := conversion.EnforcePtr(itemsPtr) if err != nil { return err } if items.Type() == objectSliceType { items.Set(reflect.ValueOf(objects)) return nil } slice := reflect.MakeSlice(items.Type(), len(objects), len(objects)) for i := range objects { dest := slice.Index(i) src, err := conversion.EnforcePtr(objects[i]) if err != nil { return err } if src.Type().AssignableTo(dest.Type()) { dest.Set(src) } else if src.Type().ConvertibleTo(dest.Type()) { dest.Set(src.Convert(dest.Type())) } else { return fmt.Errorf("item[%d]: Type mismatch: Expected %v, got %v", i, dest.Type(), src.Type()) } } items.Set(slice) return nil }
// ExtractList returns obj's Items element as an array of runtime.Objects. // Returns an error if obj is not a List type (does not have an Items member). func ExtractList(obj runtime.Object) ([]runtime.Object, error) { itemsPtr, err := GetItemsPtr(obj) if err != nil { return nil, err } items, err := conversion.EnforcePtr(itemsPtr) if err != nil { return nil, err } list := make([]runtime.Object, items.Len()) for i := range list { raw := items.Index(i) switch item := raw.Interface().(type) { case runtime.Object: list[i] = item case runtime.RawExtension: list[i] = &runtime.Unknown{ RawJSON: item.RawJSON, } default: var found bool if list[i], found = raw.Addr().Interface().(runtime.Object); !found { return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind()) } } } return list, nil }
// ListMetaFor returns a pointer to a provided object's ListMeta, // or an error if the object does not have that pointer. // TODO: allow runtime.Unknown to extract this object func ListMetaFor(obj runtime.Object) (*unversioned.ListMeta, error) { v, err := conversion.EnforcePtr(obj) if err != nil { return nil, err } var meta *unversioned.ListMeta err = runtime.FieldPtr(v, "ListMeta", &meta) return meta, err }
func listToItems(listObj runtime.Object) ([]runtime.Object, error) { v, err := conversion.EnforcePtr(listObj) if err != nil { return nil, fmt.Errorf("unexpected error: %v", err) } items := v.FieldByName("Items") if !items.IsValid() { return nil, fmt.Errorf("unexpected Items field in %v", listObj) } if items.Type().Kind() != reflect.Slice { return nil, fmt.Errorf("unexpected Items field type: %v", items.Type().Kind()) } result := make([]runtime.Object, items.Len()) for i := 0; i < items.Len(); i++ { result[i] = items.Index(i).Addr().Interface().(runtime.Object) } return result, nil }
// Accessor takes an arbitrary object pointer and returns meta.Interface. // obj must be a pointer to an API type. An error is returned if the minimum // required fields are missing. Fields that are not required return the default // value and are a no-op if set. // TODO: add a fast path for *TypeMeta and *ObjectMeta for internal objects func Accessor(obj interface{}) (Interface, error) { v, err := conversion.EnforcePtr(obj) if err != nil { return nil, err } t := v.Type() if v.Kind() != reflect.Struct { return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface()) } typeMeta := v.FieldByName("TypeMeta") if !typeMeta.IsValid() { return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t) } a := &genericAccessor{} if err := extractFromTypeMeta(typeMeta, a); err != nil { return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err) } objectMeta := v.FieldByName("ObjectMeta") if objectMeta.IsValid() { // look for the ObjectMeta fields if err := extractFromObjectMeta(objectMeta, a); err != nil { return nil, fmt.Errorf("unable to find object fields on %#v: %v", objectMeta, err) } } else { listMeta := v.FieldByName("ListMeta") if listMeta.IsValid() { // look for the ListMeta fields if err := extractFromListMeta(listMeta, a); err != nil { return nil, fmt.Errorf("unable to find list fields on %#v: %v", listMeta, err) } } else { // look for the older TypeMeta with all metadata if err := extractFromObjectMeta(typeMeta, a); err != nil { return nil, fmt.Errorf("unable to find object fields on %#v: %v", typeMeta, err) } } } return a, nil }
// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion // and Kind of an in-memory internal object. // TODO: this interface is used to test code that does not have ObjectMeta or ListMeta // in round tripping (objects which can use apiVersion/kind, but do not fit the Kube // api conventions). func TypeAccessor(obj interface{}) (TypeInterface, error) { v, err := conversion.EnforcePtr(obj) if err != nil { return nil, err } t := v.Type() if v.Kind() != reflect.Struct { return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface()) } typeMeta := v.FieldByName("TypeMeta") if !typeMeta.IsValid() { return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t) } a := &genericAccessor{} if err := extractFromTypeMeta(typeMeta, a); err != nil { return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err) } return a, nil }
// fieldPtr puts the address of fieldName, which must be a member of v, // into dest, which must be an address of a variable to which this field's // address can be assigned. func FieldPtr(v reflect.Value, fieldName string, dest interface{}) error { field := v.FieldByName(fieldName) if !field.IsValid() { return fmt.Errorf("couldn't find %v field in %#v", fieldName, v.Interface()) } v, err := conversion.EnforcePtr(dest) if err != nil { return err } field = field.Addr() if field.Type().AssignableTo(v.Type()) { v.Set(field) return nil } if field.Type().ConvertibleTo(v.Type()) { v.Set(field.Convert(v.Type())) return nil } return fmt.Errorf("couldn't assign/convert %v to %v", field.Type(), v.Type()) }
// GetItemsPtr returns a pointer to the list object's Items member. // If 'list' doesn't have an Items member, it's not really a list type // and an error will be returned. // This function will either return a pointer to a slice, or an error, but not both. func GetItemsPtr(list runtime.Object) (interface{}, error) { v, err := conversion.EnforcePtr(list) if err != nil { return nil, err } items := v.FieldByName("Items") if !items.IsValid() { return nil, fmt.Errorf("no Items field in %#v", list) } switch items.Kind() { case reflect.Interface, reflect.Ptr: target := reflect.TypeOf(items.Interface()).Elem() if target.Kind() != reflect.Slice { return nil, fmt.Errorf("items: Expected slice, got %s", target.Kind()) } return items.Interface(), nil case reflect.Slice: return items.Addr().Interface(), nil default: return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind()) } }