Add more parameters to Watch

* Add labels selector (same as List)
* Add fields selector
 * Plan to let you select pods by Host and/or Status
* Add resourceVersion to let you resume a watch where you left off.
This commit is contained in:
Daniel Smith
2014-08-05 13:33:25 -07:00
parent d52492111f
commit 283fdba6ab
11 changed files with 182 additions and 46 deletions

View File

@@ -296,18 +296,19 @@ func Everything(interface{}) bool {
// WatchList begins watching the specified key's items. Items are decoded into
// API objects, and any items passing 'filter' are sent down the returned
// watch.Interface.
func (h *EtcdHelper) WatchList(key string, filter FilterFunc) (watch.Interface, error) {
// watch.Interface. resourceVersion may be used to specify what version to begin
// watching (e.g., for reconnecting without missing any updateds).
func (h *EtcdHelper) WatchList(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
w := newEtcdWatcher(true, filter, h.Codec)
go w.etcdWatch(h.Client, key)
go w.etcdWatch(h.Client, key, resourceVersion)
return w, nil
}
// Watch begins watching the specified key. Events are decoded into
// API objects and sent down the returned watch.Interface.
func (h *EtcdHelper) Watch(key string) (watch.Interface, error) {
func (h *EtcdHelper) Watch(key string, resourceVersion uint64) (watch.Interface, error) {
w := newEtcdWatcher(false, nil, h.Codec)
go w.etcdWatch(h.Client, key)
go w.etcdWatch(h.Client, key, resourceVersion)
return w, nil
}
@@ -350,10 +351,10 @@ func newEtcdWatcher(list bool, filter FilterFunc, encoding Codec) *etcdWatcher {
// etcdWatch calls etcd's Watch function, and handles any errors. Meant to be called
// as a goroutine.
func (w *etcdWatcher) etcdWatch(client EtcdGetSet, key string) {
func (w *etcdWatcher) etcdWatch(client EtcdGetSet, key string, resourceVersion uint64) {
defer util.HandleCrash()
defer close(w.etcdCallEnded)
_, err := client.Watch(key, 0, w.list, w.etcdIncoming, w.etcdStop)
_, err := client.Watch(key, resourceVersion, w.list, w.etcdIncoming, w.etcdStop)
if err != etcd.ErrWatchStoppedByUser {
glog.Errorf("etcd.Watch stopped unexpectedly: %v (%#v)", err, err)
}
@@ -385,18 +386,20 @@ func (w *etcdWatcher) sendResult(res *etcd.Response) {
var action watch.EventType
var data []byte
switch res.Action {
case "create", "set":
case "create":
if res.Node == nil {
glog.Errorf("unexpected nil node: %#v", res)
return
}
data = []byte(res.Node.Value)
// TODO: Is this conditional correct?
if res.EtcdIndex > 0 {
action = watch.Modified
} else {
action = watch.Added
action = watch.Added
case "set":
if res.Node == nil {
glog.Errorf("unexpected nil node: %#v", res)
return
}
data = []byte(res.Node.Value)
action = watch.Modified
case "delete":
if res.PrevNode == nil {
glog.Errorf("unexpected nil prev node: %#v", res)

View File

@@ -325,6 +325,30 @@ func TestAtomicUpdate_CreateCollision(t *testing.T) {
}
}
func TestWatchInterpretation_ListCreate(t *testing.T) {
w := newEtcdWatcher(true, func(interface{}) bool {
t.Errorf("unexpected filter call")
return true
}, encoding)
pod := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
podBytes, _ := encoding.Encode(pod)
go w.sendResult(&etcd.Response{
Action: "create",
Node: &etcd.Node{
Value: string(podBytes),
},
})
got := <-w.outgoing
if e, a := watch.Added, got.Type; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e, a := pod, got.Object; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %v, got %v", e, a)
}
}
func TestWatchInterpretation_ListAdd(t *testing.T) {
w := newEtcdWatcher(true, func(interface{}) bool {
t.Errorf("unexpected filter call")
@@ -341,7 +365,7 @@ func TestWatchInterpretation_ListAdd(t *testing.T) {
})
got := <-w.outgoing
if e, a := watch.Added, got.Type; e != a {
if e, a := watch.Modified, got.Type; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e, a := pod, got.Object; !reflect.DeepEqual(e, a) {
@@ -420,7 +444,7 @@ func TestWatch(t *testing.T) {
fakeClient := MakeFakeEtcdClient(t)
h := EtcdHelper{fakeClient, codec, versioner}
watching, err := h.Watch("/some/key")
watching, err := h.Watch("/some/key", 0)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@@ -438,7 +462,7 @@ func TestWatch(t *testing.T) {
}
event := <-watching.ResultChan()
if e, a := watch.Added, event.Type; e != a {
if e, a := watch.Modified, event.Type; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e, a := pod, event.Object; !reflect.DeepEqual(e, a) {
@@ -462,7 +486,7 @@ func TestWatchPurposefulShutdown(t *testing.T) {
h := EtcdHelper{fakeClient, codec, versioner}
// Test purposeful shutdown
watching, err := h.Watch("/some/key")
watching, err := h.Watch("/some/key", 0)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}