mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-17 15:13:08 +00:00
Expose REST resource for endpoints and watch on services/endpoints
Will allow kube-proxies to listen on endpoints.
This commit is contained in:
@@ -340,10 +340,54 @@ func (r *Registry) UpdateService(svc api.Service) error {
|
||||
return r.SetObj(makeServiceKey(svc.ID), svc)
|
||||
}
|
||||
|
||||
// WatchServices begins watching for new, changed, or deleted service configurations.
|
||||
func (r *Registry) WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||
if !label.Empty() {
|
||||
return nil, fmt.Errorf("label selectors are not supported on services")
|
||||
}
|
||||
if value, found := field.RequiresExactMatch("ID"); found {
|
||||
return r.Watch(makeServiceKey(value), resourceVersion)
|
||||
}
|
||||
if field.Empty() {
|
||||
return r.WatchList("/registry/services/specs", resourceVersion, tools.Everything)
|
||||
}
|
||||
return nil, fmt.Errorf("only the 'ID' and default (everything) field selectors are supported")
|
||||
}
|
||||
|
||||
// GetEndpoints obtains endpoints specified by a service name
|
||||
func (r *Registry) GetEndpoints(name string) (*api.Endpoints, error) {
|
||||
obj := &api.Endpoints{}
|
||||
if err := r.ExtractObj(makeServiceEndpointsKey(name), obj, false); err != nil {
|
||||
if tools.IsEtcdNotFound(err) {
|
||||
if _, err := r.GetService(name); err != nil && apiserver.IsNotFound(err) {
|
||||
return nil, apiserver.NewNotFoundErr("service", name)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// UpdateEndpoints update Endpoints of a Service.
|
||||
func (r *Registry) UpdateEndpoints(e api.Endpoints) error {
|
||||
return r.AtomicUpdate(makeServiceEndpointsKey(e.ID), &api.Endpoints{},
|
||||
func(interface{}) (interface{}, error) {
|
||||
func(input interface{}) (interface{}, error) {
|
||||
// TODO: racy - label query is returning different results for two simultaneous updaters
|
||||
return e, nil
|
||||
})
|
||||
}
|
||||
|
||||
// WatchEndpoints begins watching for new, changed, or deleted endpoint configurations.
|
||||
func (r *Registry) WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||
if !label.Empty() {
|
||||
return nil, fmt.Errorf("label selectors are not supported on endpoints")
|
||||
}
|
||||
if value, found := field.RequiresExactMatch("ID"); found {
|
||||
return r.Watch(makeServiceEndpointsKey(value), resourceVersion)
|
||||
}
|
||||
if field.Empty() {
|
||||
return r.WatchList("/registry/services/endpoints", resourceVersion, tools.Everything)
|
||||
}
|
||||
return nil, fmt.Errorf("only the 'ID' and default (everything) field selectors are supported")
|
||||
}
|
||||
|
@@ -730,7 +730,7 @@ func TestEtcdGetService(t *testing.T) {
|
||||
}
|
||||
|
||||
if service.ID != "foo" {
|
||||
t.Errorf("Unexpected pod: %#v", service)
|
||||
t.Errorf("Unexpected service: %#v", service)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,6 +803,23 @@ func TestEtcdUpdateService(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdGetEndpoints(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Set("/registry/services/endpoints/foo", api.EncodeOrDie(api.Endpoints{
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
Endpoints: []string{"127.0.0.1:34855"},
|
||||
}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient, []string{"machine"})
|
||||
endpoints, err := registry.GetEndpoints("foo")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if endpoints.ID != "foo" || !reflect.DeepEqual(endpoints.Endpoints, []string{"127.0.0.1:34855"}) {
|
||||
t.Errorf("Unexpected endpoints: %#v", endpoints)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdUpdateEndpoints(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
@@ -830,6 +847,104 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdWatchServices(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
registry := NewTestEtcdRegistry(fakeClient, []string{"machine"})
|
||||
watching, err := registry.WatchServices(
|
||||
labels.Everything(),
|
||||
labels.SelectorFromSet(labels.Set{"ID": "foo"}),
|
||||
1,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
fakeClient.WaitForWatchCompletion()
|
||||
|
||||
select {
|
||||
case _, ok := <-watching.ResultChan():
|
||||
if !ok {
|
||||
t.Errorf("watching channel should be open")
|
||||
}
|
||||
default:
|
||||
}
|
||||
fakeClient.WatchInjectError <- nil
|
||||
if _, ok := <-watching.ResultChan(); ok {
|
||||
t.Errorf("watching channel should be closed")
|
||||
}
|
||||
watching.Stop()
|
||||
}
|
||||
|
||||
func TestEtcdWatchServicesBadSelector(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
registry := NewTestEtcdRegistry(fakeClient, []string{"machine"})
|
||||
_, err := registry.WatchServices(
|
||||
labels.Everything(),
|
||||
labels.SelectorFromSet(labels.Set{"Field.Selector": "foo"}),
|
||||
0,
|
||||
)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error: %v", err)
|
||||
}
|
||||
|
||||
_, err = registry.WatchServices(
|
||||
labels.SelectorFromSet(labels.Set{"Label.Selector": "foo"}),
|
||||
labels.Everything(),
|
||||
0,
|
||||
)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdWatchEndpoints(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
registry := NewTestEtcdRegistry(fakeClient, []string{"machine"})
|
||||
watching, err := registry.WatchEndpoints(
|
||||
labels.Everything(),
|
||||
labels.SelectorFromSet(labels.Set{"ID": "foo"}),
|
||||
1,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
fakeClient.WaitForWatchCompletion()
|
||||
|
||||
select {
|
||||
case _, ok := <-watching.ResultChan():
|
||||
if !ok {
|
||||
t.Errorf("watching channel should be open")
|
||||
}
|
||||
default:
|
||||
}
|
||||
fakeClient.WatchInjectError <- nil
|
||||
if _, ok := <-watching.ResultChan(); ok {
|
||||
t.Errorf("watching channel should be closed")
|
||||
}
|
||||
watching.Stop()
|
||||
}
|
||||
|
||||
func TestEtcdWatchEndpointsBadSelector(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
registry := NewTestEtcdRegistry(fakeClient, []string{"machine"})
|
||||
_, err := registry.WatchEndpoints(
|
||||
labels.Everything(),
|
||||
labels.SelectorFromSet(labels.Set{"Field.Selector": "foo"}),
|
||||
0,
|
||||
)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error: %v", err)
|
||||
}
|
||||
|
||||
_, err = registry.WatchEndpoints(
|
||||
labels.SelectorFromSet(labels.Set{"Label.Selector": "foo"}),
|
||||
labels.Everything(),
|
||||
0,
|
||||
)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO We need a test for the compare and swap behavior. This basically requires two things:
|
||||
// 1) Add a per-operation synchronization channel to the fake etcd client, such that any operation waits on that
|
||||
// channel, this will enable us to orchestrate the flow of etcd requests in the test.
|
||||
|
Reference in New Issue
Block a user