Change:
PodInterface should have Watch method behaving in the same way as ServiceInterface.Watch does. Use case: a monitoring system (namely Prometheus) expects to get the list of monitored servers performing a DNS-SD query. Special service (similar to kube2sky shipped with Kubernetes) mirrors status of running Pods into etcd, which is in turn monitored by SkyDNS server and exported as DNS-SD. Schematically the data flow looks like this: Kubernetes -kube2sky -etcd -SkyDNS -Prometheus. The biggest challenge is to deliver list of all running pods from Kubernetes to kube2sky. Currently kube2sky can only poll Kubernetes with PodInterface.List() each N seconds, which is not efficient. Having a Watch method would be much better.
cc Do you know why we do not support watch?
Every object should support Watch.
Watching status doesn't currently work -- that's .
I agree with OP. This is just an accident of history; some boilerplate in the client isn't completely filled out. As Brian mentions, not every field is currently watchable but that's being addressed elsewhere.
This is relevant to your interests potentially w/ your work on
This is a pretty simple change if someone wants to get their feet wet. :)
I'll work on it.

Discussion:
import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" <ins> "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" </ins> ) // FakePods implements PodsInterface. Meant to be embedded into a struct to get a default

return &api.Pod{}, nil } <ins> func (c *FakePods) Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error) { c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "watch-pods", Value: resourceVersion}) return c.Fake.Watch, c.Fake.Err } </ins> func (c *FakePods) Bind(bind *api.Binding) error { c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "bind-pod", Value: bind.Name}) return nil

"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" <ins> "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" </ins> ) // PodsNamespacer has methods to work with Pod resources in a namespace

Delete(name string) error Create(pod *api.Pod) (*api.Pod, error) Update(pod *api.Pod) (*api.Pod, error) <ins> Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error) </ins> Bind(binding *api.Binding) error }

return } <ins> // Watch returns a watch.Interface that watches the requested pods. func (c *pods) Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error) { return c.r.Get(). Prefix("watch"). Namespace(c.ns). Resource("pods"). Param("resourceVersion", resourceVersion). SelectorParam("labels", label). SelectorParam("fields", field). Watch() } </ins> // Bind applies the provided binding to the named pod in the current namespace (binding.Namespace is ignored). func (c *pods) Bind(binding *api.Binding) error { return c.r.Post().Namespace(c.ns).Resource("pods").Name(binding.Name).SubResource("binding").Body(binding).Do().Error()

"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" <ins> "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" </ins> . "github.com/onsi/ginkgo" . "github.com/onsi/gomega"

}, } <ins> By("setting up watch") pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value}))) if err != nil { Fail(fmt.Sprintf("Failed to query for pods: %v", err)) } Expect(len(pods.Items)).To(Equal(0)) w, err := podClient.Watch( labels.SelectorFromSet(labels.Set(map[string]string{"time": value})), labels.Everything(), pods.ListMeta.ResourceVersion) if err != nil { Fail(fmt.Sprintf("Failed to set up watch: %v", err)) } </ins> By("submitting the pod to kubernetes") // We call defer here in case there is a problem with // the test so we can ensure that we clean up after // ourselves defer podClient.Delete(pod.Name) <del> _, err := podClient.Create(pod) </del> <ins> _, err = podClient.Create(pod) </ins> if err != nil { Fail(fmt.Sprintf("Failed to create pod: %v", err)) } By("verifying the pod is in kubernetes") <del> pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value}))) </del> <ins> pods, err = podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value}))) </ins> if err != nil { Fail(fmt.Sprintf("Failed to query for pods: %v", err)) } Expect(len(pods.Items)).To(Equal(1)) <ins> By("veryfying pod creation was observed") select { case event, _ := <-w.ResultChan(): if event.Type != watch.Added { Fail(fmt.Sprintf("Failed to observe pod creation: %v", event)) } case <-time.After(podStartTimeout): Fail("Timeout while waiting for pod creation") } </ins> By("deleting the pod") podClient.Delete(pod.Name) pods, err = podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value}))) <ins> if err != nil { Fail(fmt.Sprintf("Failed to delete pod: %v", err)) } </ins> Expect(len(pods.Items)).To(Equal(0)) <ins> By("veryfying pod deletion was observed") deleted := false timeout := false timer := time.After(podStartTimeout) for !deleted && !timeout { select { case event, _ := <-w.ResultChan(): if event.Type == watch.Deleted { deleted = true } case <-timer: timeout = true } } if !deleted { Fail("Failed to observe pod deletion") } </ins> }) It("should be updated", func() {