func TestExtractListGenericV1(t *testing.T) { pl := &v1.List{ Items: []runtime.RawExtension{ {RawJSON: []byte("foo")}, {RawJSON: []byte("bar")}, {Object: &v1.Pod{ObjectMeta: v1.ObjectMeta{Name: "other"}}}, }, } list, err := meta.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].(*runtime.Unknown); !ok { t.Fatalf("Expected list[0] to be *runtime.Unknown, it is %#v", obj) } if obj, ok := list[1].(*runtime.Unknown); !ok { t.Fatalf("Expected list[1] to be *runtime.Unknown, it is %#v", obj) } if obj, ok := list[2].(*v1.Pod); !ok { t.Fatalf("Expected list[2] to be *runtime.Unknown, it is %#v", obj) } }
func (o objects) Add(obj runtime.Object) error { gvk, err := o.scheme.ObjectKind(obj) if err != nil { return err } kind := gvk.Kind switch { case meta.IsListType(obj): if kind != "List" { o.types[kind] = append(o.types[kind], obj) } list, err := meta.ExtractList(obj) if err != nil { return err } if errs := runtime.DecodeList(list, o.decoder); len(errs) > 0 { return errs[0] } for _, obj := range list { if err := o.Add(obj); err != nil { return err } } default: if status, ok := obj.(*unversioned.Status); ok && status.Details != nil { kind = status.Details.Kind } o.types[kind] = append(o.types[kind], obj) } return nil }
func TestExtractListOfInterfacePtrs(t *testing.T) { pl := &fakePtrInterfaceList{ Items: &[]runtime.Object{}, } list, err := meta.ExtractList(pl) if err != nil { t.Fatalf("Unexpected error %v", err) } if len(list) > 0 { t.Fatalf("Expected empty list, got %#v", list) } }
func TestExtractListOfValuePtrs(t *testing.T) { pl := &fakePtrValueList{ Items: []*api.Pod{ {ObjectMeta: api.ObjectMeta{Name: "1"}}, {ObjectMeta: api.ObjectMeta{Name: "2"}}, }, } list, err := meta.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 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 := meta.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) } }
func TestExtractListV1(t *testing.T) { pl := &v1.PodList{ Items: []v1.Pod{ {ObjectMeta: v1.ObjectMeta{Name: "1"}}, {ObjectMeta: v1.ObjectMeta{Name: "2"}}, {ObjectMeta: v1.ObjectMeta{Name: "3"}}, }, } list, err := meta.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 e, a := list[i].(*v1.Pod).Name, pl.Items[i].Name; e != a { t.Fatalf("Expected %v, got %v", e, a) } } }
func TestSetExtractListRoundTrip(t *testing.T) { fuzzer := fuzz.New().NilChance(0).NumElements(1, 5) for i := 0; i < 5; i++ { start := &api.PodList{} fuzzer.Fuzz(&start.Items) list, err := meta.ExtractList(start) if err != nil { t.Errorf("Unexpected error %v", err) continue } got := &api.PodList{} err = meta.SetList(got, list) if err != nil { t.Errorf("Unexpected error %v", err) continue } if e, a := start, got; !reflect.DeepEqual(e, a) { t.Fatalf("Expected %#v, got %#v", e, a) } } }
func TestArrayOfRuntimeObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &EmbeddedTestExternal{}) s.AddKnownTypes(internalGV, &ObjectTest{}) s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &ObjectTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) innerItems := []runtime.Object{ &EmbeddedTest{ID: "baz"}, } items := []runtime.Object{ &EmbeddedTest{ID: "foo"}, &EmbeddedTest{ID: "bar"}, // TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization &runtime.Unknown{RawJSON: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`)}, &ObjectTest{ Items: runtime.NewEncodableList(codec, innerItems), }, } internal := &ObjectTest{ Items: runtime.NewEncodableList(codec, items), } wire, err := runtime.Encode(codec, internal) if err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Wire format is:\n%s\n", string(wire)) obj := &ObjectTestExternal{} if err := json.Unmarshal(wire, obj); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("exact wire is: %s", string(obj.Items[0].RawJSON)) items[3] = &ObjectTest{Items: innerItems} internal.Items = items decoded, err := runtime.Decode(codec, wire) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := meta.ExtractList(decoded) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } list2, err := meta.ExtractList(list[3]) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list2, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := meta.SetList(list[3], list2); err != nil { t.Fatalf("unexpected error: %v", err) } // we want DecodeList to set type meta if possible, even on runtime.Unknown objects internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"} if e, a := internal.Items, list; !reflect.DeepEqual(e, a) { t.Errorf("mismatched decoded: %s", util.ObjectGoPrintSideBySide(e, a)) } }
// ListAndWatch first lists all items and get the resource version at the moment of call, // and then use the resource version to watch. // It returns error if ListAndWatch didn't even try to initialize watch. func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error { var resourceVersion string resyncCh, cleanup := r.resyncChan() defer cleanup() // Explicitly set "0" as resource version - it's fine for the List() // to be served from cache and potentially be delayed relative to // etcd contents. Reflector framework will catch up via Watch() eventually. options := api.ListOptions{ResourceVersion: "0"} list, err := r.listerWatcher.List(options) if err != nil { return fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedType, err) } metaInterface, err := meta.Accessor(list) if err != nil { return fmt.Errorf("%s: Unable to understand list result %#v", r.name, list) } resourceVersion = metaInterface.GetResourceVersion() items, err := meta.ExtractList(list) if err != nil { return fmt.Errorf("%s: Unable to understand list result %#v (%v)", r.name, list, err) } if err := r.syncWith(items, resourceVersion); err != nil { return fmt.Errorf("%s: Unable to sync list result: %v", r.name, err) } r.setLastSyncResourceVersion(resourceVersion) for { options := api.ListOptions{ ResourceVersion: resourceVersion, // We want to avoid situations when resyncing is breaking the TCP connection // - see comment for 'timeoutForWatch()' for more details. TimeoutSeconds: r.timeoutForWatch(), } w, err := r.listerWatcher.Watch(options) if err != nil { switch err { case io.EOF: // watch closed normally case io.ErrUnexpectedEOF: glog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err) default: utilruntime.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedType, err)) } // If this is "connection refused" error, it means that most likely apiserver is not responsive. // It doesn't make sense to re-list all objects because most likely we will be able to restart // watch where we ended. // If that's the case wait and resend watch request. if urlError, ok := err.(*url.Error); ok { if opError, ok := urlError.Err.(*net.OpError); ok { if errno, ok := opError.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED { time.Sleep(time.Second) continue } } } return nil } if err := r.watchHandler(w, &resourceVersion, resyncCh, stopCh); err != nil { if err != errorResyncRequested && err != errorStopRequested { glog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedType, err) } return nil } if r.canForceResyncNow() { glog.V(4).Infof("%s: next resync planned for %#v, forcing now", r.name, r.nextResync) return nil } } }