Make ResourceVersion a string internally instead of uint64

Allows us to define different watch versioning regimes in the future
as well as to encode information with the resource version.

This changes /watch/resources?resourceVersion=3 to start the watch at
4 instead of 3, which means clients can read a resource version and
then send it back to the server. Clients should no longer do math on
resource versions.
This commit is contained in:
Clayton Coleman
2014-10-07 16:51:28 -04:00
parent 31e02b882b
commit 82bcdd3b3b
54 changed files with 518 additions and 240 deletions

View File

@@ -31,8 +31,8 @@ import (
type Watcher interface {
ListServices(ctx api.Context, label labels.Selector) (*api.ServiceList, error)
ListEndpoints(ctx api.Context, label labels.Selector) (*api.EndpointsList, error)
WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error)
WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error)
}
// SourceAPI implements a configuration source for services and endpoints that
@@ -57,12 +57,12 @@ func NewSourceAPI(client Watcher, period time.Duration, services chan<- ServiceU
// prevent hot loops if the server starts to misbehave
reconnectDuration: time.Second * 1,
}
serviceVersion := uint64(0)
serviceVersion := ""
go util.Forever(func() {
config.runServices(&serviceVersion)
time.Sleep(wait.Jitter(config.reconnectDuration, 0.0))
}, period)
endpointVersion := uint64(0)
endpointVersion := ""
go util.Forever(func() {
config.runEndpoints(&endpointVersion)
time.Sleep(wait.Jitter(config.reconnectDuration, 0.0))
@@ -71,9 +71,9 @@ func NewSourceAPI(client Watcher, period time.Duration, services chan<- ServiceU
}
// runServices loops forever looking for changes to services.
func (s *SourceAPI) runServices(resourceVersion *uint64) {
func (s *SourceAPI) runServices(resourceVersion *string) {
ctx := api.NewContext()
if *resourceVersion == 0 {
if len(*resourceVersion) == 0 {
services, err := s.client.ListServices(ctx, labels.Everything())
if err != nil {
glog.Errorf("Unable to load services: %v", err)
@@ -97,7 +97,7 @@ func (s *SourceAPI) runServices(resourceVersion *uint64) {
}
// handleServicesWatch loops over an event channel and delivers config changes to an update channel.
func handleServicesWatch(resourceVersion *uint64, ch <-chan watch.Event, updates chan<- ServiceUpdate) {
func handleServicesWatch(resourceVersion *string, ch <-chan watch.Event, updates chan<- ServiceUpdate) {
for {
select {
case event, ok := <-ch:
@@ -107,7 +107,7 @@ func handleServicesWatch(resourceVersion *uint64, ch <-chan watch.Event, updates
}
service := event.Object.(*api.Service)
*resourceVersion = service.ResourceVersion + 1
*resourceVersion = service.ResourceVersion
switch event.Type {
case watch.Added, watch.Modified:
@@ -121,9 +121,9 @@ func handleServicesWatch(resourceVersion *uint64, ch <-chan watch.Event, updates
}
// runEndpoints loops forever looking for changes to endpoints.
func (s *SourceAPI) runEndpoints(resourceVersion *uint64) {
func (s *SourceAPI) runEndpoints(resourceVersion *string) {
ctx := api.NewContext()
if *resourceVersion == 0 {
if len(*resourceVersion) == 0 {
endpoints, err := s.client.ListEndpoints(ctx, labels.Everything())
if err != nil {
glog.Errorf("Unable to load endpoints: %v", err)
@@ -147,7 +147,7 @@ func (s *SourceAPI) runEndpoints(resourceVersion *uint64) {
}
// handleEndpointsWatch loops over an event channel and delivers config changes to an update channel.
func handleEndpointsWatch(resourceVersion *uint64, ch <-chan watch.Event, updates chan<- EndpointsUpdate) {
func handleEndpointsWatch(resourceVersion *string, ch <-chan watch.Event, updates chan<- EndpointsUpdate) {
for {
select {
case event, ok := <-ch:
@@ -157,7 +157,7 @@ func handleEndpointsWatch(resourceVersion *uint64, ch <-chan watch.Event, update
}
endpoints := event.Object.(*api.Endpoints)
*resourceVersion = endpoints.ResourceVersion + 1
*resourceVersion = endpoints.ResourceVersion
switch event.Type {
case watch.Added, watch.Modified:

View File

@@ -27,13 +27,13 @@ import (
)
func TestServices(t *testing.T) {
service := api.Service{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: uint64(2)}}
service := api.Service{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: "2"}}
fakeWatch := watch.NewFake()
fakeClient := &client.Fake{Watch: fakeWatch}
services := make(chan ServiceUpdate)
source := SourceAPI{client: fakeClient, services: services}
resourceVersion := uint64(1)
resourceVersion := "1"
go func() {
// called twice
source.runServices(&resourceVersion)
@@ -42,7 +42,7 @@ func TestServices(t *testing.T) {
// test adding a service to the watch
fakeWatch.Add(&service)
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-services", uint64(1)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-services", "1"}}) {
t.Errorf("expected call to watch-services, got %#v", fakeClient)
}
@@ -66,26 +66,26 @@ func TestServices(t *testing.T) {
fakeWatch.Stop()
newFakeWatch.Add(&service)
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-services", uint64(1)}, {"watch-services", uint64(3)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-services", "1"}, {"watch-services", "3"}}) {
t.Errorf("expected call to watch-endpoints, got %#v", fakeClient)
}
}
func TestServicesFromZero(t *testing.T) {
service := api.Service{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: uint64(2)}}
service := api.Service{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: "2"}}
fakeWatch := watch.NewFake()
fakeWatch.Stop()
fakeClient := &client.Fake{Watch: fakeWatch}
fakeClient.ServiceList = api.ServiceList{
TypeMeta: api.TypeMeta{ResourceVersion: 2},
TypeMeta: api.TypeMeta{ResourceVersion: "2"},
Items: []api.Service{
service,
},
}
services := make(chan ServiceUpdate)
source := SourceAPI{client: fakeClient, services: services}
resourceVersion := uint64(0)
resourceVersion := ""
ch := make(chan struct{})
go func() {
source.runServices(&resourceVersion)
@@ -101,10 +101,10 @@ func TestServicesFromZero(t *testing.T) {
// should have listed, then watched
<-ch
if resourceVersion != 2 {
if resourceVersion != "2" {
t.Errorf("unexpected resource version, got %#v", resourceVersion)
}
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"list-services", nil}, {"watch-services", uint64(2)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"list-services", nil}, {"watch-services", "2"}}) {
t.Errorf("unexpected actions, got %#v", fakeClient)
}
}
@@ -113,7 +113,7 @@ func TestServicesError(t *testing.T) {
fakeClient := &client.Fake{Err: errors.New("test")}
services := make(chan ServiceUpdate)
source := SourceAPI{client: fakeClient, services: services}
resourceVersion := uint64(1)
resourceVersion := "1"
ch := make(chan struct{})
go func() {
source.runServices(&resourceVersion)
@@ -122,10 +122,10 @@ func TestServicesError(t *testing.T) {
// should have listed only
<-ch
if resourceVersion != 1 {
if resourceVersion != "1" {
t.Errorf("unexpected resource version, got %#v", resourceVersion)
}
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-services", uint64(1)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-services", "1"}}) {
t.Errorf("unexpected actions, got %#v", fakeClient)
}
}
@@ -134,7 +134,7 @@ func TestServicesFromZeroError(t *testing.T) {
fakeClient := &client.Fake{Err: errors.New("test")}
services := make(chan ServiceUpdate)
source := SourceAPI{client: fakeClient, services: services}
resourceVersion := uint64(0)
resourceVersion := ""
ch := make(chan struct{})
go func() {
source.runServices(&resourceVersion)
@@ -143,7 +143,7 @@ func TestServicesFromZeroError(t *testing.T) {
// should have listed only
<-ch
if resourceVersion != 0 {
if resourceVersion != "" {
t.Errorf("unexpected resource version, got %#v", resourceVersion)
}
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"list-services", nil}}) {
@@ -152,13 +152,13 @@ func TestServicesFromZeroError(t *testing.T) {
}
func TestEndpoints(t *testing.T) {
endpoint := api.Endpoints{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: uint64(2)}, Endpoints: []string{"127.0.0.1:9000"}}
endpoint := api.Endpoints{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: "2"}, Endpoints: []string{"127.0.0.1:9000"}}
fakeWatch := watch.NewFake()
fakeClient := &client.Fake{Watch: fakeWatch}
endpoints := make(chan EndpointsUpdate)
source := SourceAPI{client: fakeClient, endpoints: endpoints}
resourceVersion := uint64(1)
resourceVersion := "1"
go func() {
// called twice
source.runEndpoints(&resourceVersion)
@@ -167,7 +167,7 @@ func TestEndpoints(t *testing.T) {
// test adding an endpoint to the watch
fakeWatch.Add(&endpoint)
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-endpoints", uint64(1)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-endpoints", "1"}}) {
t.Errorf("expected call to watch-endpoints, got %#v", fakeClient)
}
@@ -191,26 +191,26 @@ func TestEndpoints(t *testing.T) {
fakeWatch.Stop()
newFakeWatch.Add(&endpoint)
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-endpoints", uint64(1)}, {"watch-endpoints", uint64(3)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-endpoints", "1"}, {"watch-endpoints", "3"}}) {
t.Errorf("expected call to watch-endpoints, got %#v", fakeClient)
}
}
func TestEndpointsFromZero(t *testing.T) {
endpoint := api.Endpoints{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: uint64(2)}, Endpoints: []string{"127.0.0.1:9000"}}
endpoint := api.Endpoints{TypeMeta: api.TypeMeta{ID: "bar", ResourceVersion: "2"}, Endpoints: []string{"127.0.0.1:9000"}}
fakeWatch := watch.NewFake()
fakeWatch.Stop()
fakeClient := &client.Fake{Watch: fakeWatch}
fakeClient.EndpointsList = api.EndpointsList{
TypeMeta: api.TypeMeta{ResourceVersion: 2},
TypeMeta: api.TypeMeta{ResourceVersion: "2"},
Items: []api.Endpoints{
endpoint,
},
}
endpoints := make(chan EndpointsUpdate)
source := SourceAPI{client: fakeClient, endpoints: endpoints}
resourceVersion := uint64(0)
resourceVersion := ""
ch := make(chan struct{})
go func() {
source.runEndpoints(&resourceVersion)
@@ -226,10 +226,10 @@ func TestEndpointsFromZero(t *testing.T) {
// should have listed, then watched
<-ch
if resourceVersion != 2 {
if resourceVersion != "2" {
t.Errorf("unexpected resource version, got %#v", resourceVersion)
}
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"list-endpoints", nil}, {"watch-endpoints", uint64(2)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"list-endpoints", nil}, {"watch-endpoints", "2"}}) {
t.Errorf("unexpected actions, got %#v", fakeClient)
}
}
@@ -238,7 +238,7 @@ func TestEndpointsError(t *testing.T) {
fakeClient := &client.Fake{Err: errors.New("test")}
endpoints := make(chan EndpointsUpdate)
source := SourceAPI{client: fakeClient, endpoints: endpoints}
resourceVersion := uint64(1)
resourceVersion := "1"
ch := make(chan struct{})
go func() {
source.runEndpoints(&resourceVersion)
@@ -247,10 +247,10 @@ func TestEndpointsError(t *testing.T) {
// should have listed only
<-ch
if resourceVersion != 1 {
if resourceVersion != "1" {
t.Errorf("unexpected resource version, got %#v", resourceVersion)
}
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-endpoints", uint64(1)}}) {
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"watch-endpoints", "1"}}) {
t.Errorf("unexpected actions, got %#v", fakeClient)
}
}
@@ -259,7 +259,7 @@ func TestEndpointsFromZeroError(t *testing.T) {
fakeClient := &client.Fake{Err: errors.New("test")}
endpoints := make(chan EndpointsUpdate)
source := SourceAPI{client: fakeClient, endpoints: endpoints}
resourceVersion := uint64(0)
resourceVersion := ""
ch := make(chan struct{})
go func() {
source.runEndpoints(&resourceVersion)
@@ -268,7 +268,7 @@ func TestEndpointsFromZeroError(t *testing.T) {
// should have listed only
<-ch
if resourceVersion != 0 {
if resourceVersion != "" {
t.Errorf("unexpected resource version, got %#v", resourceVersion)
}
if !reflect.DeepEqual(fakeClient.Actions, []client.FakeAction{{"list-endpoints", nil}}) {