mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Simplify proxy config for Services by removing Mux.
This commit is contained in:
		@@ -305,19 +305,14 @@ func NewProxyServerDefault(config *options.ProxyServerConfig) (*ProxyServer, err
 | 
				
			|||||||
	// Note: RegisterHandler() calls need to happen before creation of Sources because sources
 | 
						// Note: RegisterHandler() calls need to happen before creation of Sources because sources
 | 
				
			||||||
	// only notify on changes, and the initial update (on process start) may be lost if no handlers
 | 
						// only notify on changes, and the initial update (on process start) may be lost if no handlers
 | 
				
			||||||
	// are registered yet.
 | 
						// are registered yet.
 | 
				
			||||||
	serviceConfig := proxyconfig.NewServiceConfig()
 | 
						serviceConfig := proxyconfig.NewServiceConfig(client.Core().RESTClient(), config.ConfigSyncPeriod)
 | 
				
			||||||
	serviceConfig.RegisterHandler(proxier)
 | 
						serviceConfig.RegisterHandler(proxier)
 | 
				
			||||||
 | 
						go serviceConfig.Run(wait.NeverStop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endpointsConfig := proxyconfig.NewEndpointsConfig(client.Core().RESTClient(), config.ConfigSyncPeriod)
 | 
						endpointsConfig := proxyconfig.NewEndpointsConfig(client.Core().RESTClient(), config.ConfigSyncPeriod)
 | 
				
			||||||
	endpointsConfig.RegisterHandler(endpointsHandler)
 | 
						endpointsConfig.RegisterHandler(endpointsHandler)
 | 
				
			||||||
	go endpointsConfig.Run(wait.NeverStop)
 | 
						go endpointsConfig.Run(wait.NeverStop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	proxyconfig.NewSourceAPI(
 | 
					 | 
				
			||||||
		client.Core().RESTClient(),
 | 
					 | 
				
			||||||
		config.ConfigSyncPeriod,
 | 
					 | 
				
			||||||
		serviceConfig.Channel("api"),
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	config.NodeRef = &clientv1.ObjectReference{
 | 
						config.NodeRef = &clientv1.ObjectReference{
 | 
				
			||||||
		Kind:      "Node",
 | 
							Kind:      "Node",
 | 
				
			||||||
		Name:      hostname,
 | 
							Name:      hostname,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,7 +136,7 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		iptInterface := fakeiptables.NewFake()
 | 
							iptInterface := fakeiptables.NewFake()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		serviceConfig := proxyconfig.NewServiceConfig()
 | 
							serviceConfig := proxyconfig.NewServiceConfig(internalClientset.Core().RESTClient(), 15*time.Minute)
 | 
				
			||||||
		serviceConfig.RegisterHandler(&kubemark.FakeProxyHandler{})
 | 
							serviceConfig.RegisterHandler(&kubemark.FakeProxyHandler{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		endpointsConfig := proxyconfig.NewEndpointsConfig(internalClientset.Core().RESTClient(), 15*time.Minute)
 | 
							endpointsConfig := proxyconfig.NewEndpointsConfig(internalClientset.Core().RESTClient(), 15*time.Minute)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,6 @@ limitations under the License.
 | 
				
			|||||||
package kubemark
 | 
					package kubemark
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
						v1core "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
				
			||||||
@@ -74,11 +72,7 @@ func NewHollowProxyOrDie(
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go endpointsConfig.Run(wait.NeverStop)
 | 
						go endpointsConfig.Run(wait.NeverStop)
 | 
				
			||||||
	proxyconfig.NewSourceAPI(
 | 
						go serviceConfig.Run(wait.NeverStop)
 | 
				
			||||||
		client.Core().RESTClient(),
 | 
					 | 
				
			||||||
		15*time.Minute,
 | 
					 | 
				
			||||||
		serviceConfig.Channel("api"),
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hollowProxy, err := proxyapp.NewProxyServer(client, eventClient, config, iptInterface, &FakeProxier{}, broadcaster, recorder, nil, "fake")
 | 
						hollowProxy, err := proxyapp.NewProxyServer(client, eventClient, config, iptInterface, &FakeProxier{}, broadcaster, recorder, nil, "fake")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,6 @@ load(
 | 
				
			|||||||
go_library(
 | 
					go_library(
 | 
				
			||||||
    name = "go_default_library",
 | 
					    name = "go_default_library",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        "api.go",
 | 
					 | 
				
			||||||
        "config.go",
 | 
					        "config.go",
 | 
				
			||||||
        "doc.go",
 | 
					        "doc.go",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
@@ -20,14 +19,11 @@ go_library(
 | 
				
			|||||||
        "//pkg/api:go_default_library",
 | 
					        "//pkg/api:go_default_library",
 | 
				
			||||||
        "//pkg/client/listers/core/internalversion:go_default_library",
 | 
					        "//pkg/client/listers/core/internalversion:go_default_library",
 | 
				
			||||||
        "//pkg/util/config:go_default_library",
 | 
					        "//pkg/util/config:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/davecgh/go-spew/spew",
 | 
					 | 
				
			||||||
        "//vendor:github.com/golang/glog",
 | 
					        "//vendor:github.com/golang/glog",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/fields",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/fields",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/labels",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/labels",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/types",
 | 
					 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/runtime",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/util/runtime",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/wait",
 | 
					 | 
				
			||||||
        "//vendor:k8s.io/client-go/tools/cache",
 | 
					        "//vendor:k8s.io/client-go/tools/cache",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -42,7 +38,6 @@ go_test(
 | 
				
			|||||||
    tags = ["automanaged"],
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
    deps = [
 | 
					    deps = [
 | 
				
			||||||
        "//pkg/api:go_default_library",
 | 
					        "//pkg/api:go_default_library",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/api/equality",
 | 
					 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/runtime",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/runtime",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/wait",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/util/wait",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,109 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
Copyright 2014 The Kubernetes Authors.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					 | 
				
			||||||
You may obtain a copy of the License at
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					 | 
				
			||||||
limitations under the License.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/fields"
 | 
					 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
					 | 
				
			||||||
	"k8s.io/client-go/tools/cache"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewSourceAPI creates config source that watches for changes to the services and endpoints.
 | 
					 | 
				
			||||||
func NewSourceAPI(c cache.Getter, period time.Duration, servicesChan chan<- ServiceUpdate) {
 | 
					 | 
				
			||||||
	servicesLW := cache.NewListWatchFromClient(c, "services", metav1.NamespaceAll, fields.Everything())
 | 
					 | 
				
			||||||
	newSourceAPI(servicesLW, period, servicesChan, wait.NeverStop)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newSourceAPI(
 | 
					 | 
				
			||||||
	servicesLW cache.ListerWatcher,
 | 
					 | 
				
			||||||
	period time.Duration,
 | 
					 | 
				
			||||||
	servicesChan chan<- ServiceUpdate,
 | 
					 | 
				
			||||||
	stopCh <-chan struct{}) {
 | 
					 | 
				
			||||||
	serviceController := NewServiceController(servicesLW, period, servicesChan)
 | 
					 | 
				
			||||||
	go serviceController.Run(stopCh)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !cache.WaitForCacheSync(stopCh, serviceController.HasSynced) {
 | 
					 | 
				
			||||||
		utilruntime.HandleError(fmt.Errorf("source controllers not synced"))
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	servicesChan <- ServiceUpdate{Op: SYNCED}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func sendAddService(servicesChan chan<- ServiceUpdate) func(obj interface{}) {
 | 
					 | 
				
			||||||
	return func(obj interface{}) {
 | 
					 | 
				
			||||||
		service, ok := obj.(*api.Service)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			utilruntime.HandleError(fmt.Errorf("cannot convert to *api.Service: %v", obj))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		servicesChan <- ServiceUpdate{Op: ADD, Service: service}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func sendUpdateService(servicesChan chan<- ServiceUpdate) func(oldObj, newObj interface{}) {
 | 
					 | 
				
			||||||
	return func(_, newObj interface{}) {
 | 
					 | 
				
			||||||
		service, ok := newObj.(*api.Service)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			utilruntime.HandleError(fmt.Errorf("cannot convert to *api.Service: %v", newObj))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		servicesChan <- ServiceUpdate{Op: UPDATE, Service: service}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func sendDeleteService(servicesChan chan<- ServiceUpdate) func(obj interface{}) {
 | 
					 | 
				
			||||||
	return func(obj interface{}) {
 | 
					 | 
				
			||||||
		var service *api.Service
 | 
					 | 
				
			||||||
		switch t := obj.(type) {
 | 
					 | 
				
			||||||
		case *api.Service:
 | 
					 | 
				
			||||||
			service = t
 | 
					 | 
				
			||||||
		case cache.DeletedFinalStateUnknown:
 | 
					 | 
				
			||||||
			var ok bool
 | 
					 | 
				
			||||||
			service, ok = t.Obj.(*api.Service)
 | 
					 | 
				
			||||||
			if !ok {
 | 
					 | 
				
			||||||
				utilruntime.HandleError(fmt.Errorf("cannot convert to *api.Service: %v", t.Obj))
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			utilruntime.HandleError(fmt.Errorf("cannot convert to *api.Service: %v", t))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		servicesChan <- ServiceUpdate{Op: REMOVE, Service: service}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewServiceController creates a controller that is watching services and sending
 | 
					 | 
				
			||||||
// updates into ServiceUpdate channel.
 | 
					 | 
				
			||||||
func NewServiceController(lw cache.ListerWatcher, period time.Duration, ch chan<- ServiceUpdate) cache.Controller {
 | 
					 | 
				
			||||||
	_, serviceController := cache.NewInformer(
 | 
					 | 
				
			||||||
		lw,
 | 
					 | 
				
			||||||
		&api.Service{},
 | 
					 | 
				
			||||||
		period,
 | 
					 | 
				
			||||||
		cache.ResourceEventHandlerFuncs{
 | 
					 | 
				
			||||||
			AddFunc:    sendAddService(ch),
 | 
					 | 
				
			||||||
			UpdateFunc: sendUpdateService(ch),
 | 
					 | 
				
			||||||
			DeleteFunc: sendDeleteService(ch),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	return serviceController
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -23,10 +23,8 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
					 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/watch"
 | 
						"k8s.io/apimachinery/pkg/watch"
 | 
				
			||||||
	"k8s.io/client-go/tools/cache"
 | 
						"k8s.io/client-go/tools/cache"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
@@ -65,68 +63,40 @@ func TestNewServicesSourceApi_UpdatesAndMultipleServices(t *testing.T) {
 | 
				
			|||||||
		watchResp: fakeWatch,
 | 
							watchResp: fakeWatch,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ch := make(chan ServiceUpdate)
 | 
						stopCh := make(chan struct{})
 | 
				
			||||||
 | 
						defer close(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serviceController := NewServiceController(lw, 30*time.Second, ch)
 | 
						ch := make(chan struct{})
 | 
				
			||||||
	go serviceController.Run(wait.NeverStop)
 | 
						handler := newSvcHandler(t, nil, func() { ch <- struct{}{} })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serviceConfig := newServiceConfig(lw, time.Minute)
 | 
				
			||||||
 | 
						serviceConfig.RegisterHandler(handler)
 | 
				
			||||||
 | 
						go serviceConfig.Run(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add the first service
 | 
						// Add the first service
 | 
				
			||||||
 | 
						handler.expected = []api.Service{*service1v1}
 | 
				
			||||||
	fakeWatch.Add(service1v1)
 | 
						fakeWatch.Add(service1v1)
 | 
				
			||||||
	got, ok := <-ch
 | 
						<-ch
 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		t.Errorf("Unable to read from channel when expected")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	expected := ServiceUpdate{Op: ADD, Service: service1v1}
 | 
					 | 
				
			||||||
	if !apiequality.Semantic.DeepEqual(expected, got) {
 | 
					 | 
				
			||||||
		t.Errorf("Expected %#v; Got %#v", expected, got)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add another service
 | 
						// Add another service
 | 
				
			||||||
 | 
						handler.expected = []api.Service{*service1v1, *service2}
 | 
				
			||||||
	fakeWatch.Add(service2)
 | 
						fakeWatch.Add(service2)
 | 
				
			||||||
	got, ok = <-ch
 | 
						<-ch
 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		t.Errorf("Unable to read from channel when expected")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// Could be sorted either of these two ways:
 | 
					 | 
				
			||||||
	expected = ServiceUpdate{Op: ADD, Service: service2}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !apiequality.Semantic.DeepEqual(expected, got) {
 | 
					 | 
				
			||||||
		t.Errorf("Expected %#v, Got %#v", expected, got)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Modify service1
 | 
						// Modify service1
 | 
				
			||||||
 | 
						handler.expected = []api.Service{*service1v2, *service2}
 | 
				
			||||||
	fakeWatch.Modify(service1v2)
 | 
						fakeWatch.Modify(service1v2)
 | 
				
			||||||
	got, ok = <-ch
 | 
						<-ch
 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		t.Errorf("Unable to read from channel when expected")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	expected = ServiceUpdate{Op: UPDATE, Service: service1v2}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !apiequality.Semantic.DeepEqual(expected, got) {
 | 
					 | 
				
			||||||
		t.Errorf("Expected %#v, Got %#v", expected, got)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Delete service1
 | 
						// Delete service1
 | 
				
			||||||
 | 
						handler.expected = []api.Service{*service2}
 | 
				
			||||||
	fakeWatch.Delete(service1v2)
 | 
						fakeWatch.Delete(service1v2)
 | 
				
			||||||
	got, ok = <-ch
 | 
						<-ch
 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		t.Errorf("Unable to read from channel when expected")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	expected = ServiceUpdate{Op: REMOVE, Service: service1v2}
 | 
					 | 
				
			||||||
	if !apiequality.Semantic.DeepEqual(expected, got) {
 | 
					 | 
				
			||||||
		t.Errorf("Expected %#v, Got %#v", expected, got)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Delete service2
 | 
						// Delete service2
 | 
				
			||||||
 | 
						handler.expected = []api.Service{}
 | 
				
			||||||
	fakeWatch.Delete(service2)
 | 
						fakeWatch.Delete(service2)
 | 
				
			||||||
	got, ok = <-ch
 | 
						<-ch
 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		t.Errorf("Unable to read from channel when expected")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	expected = ServiceUpdate{Op: REMOVE, Service: service2}
 | 
					 | 
				
			||||||
	if !apiequality.Semantic.DeepEqual(expected, got) {
 | 
					 | 
				
			||||||
		t.Errorf("Expected %#v, Got %#v", expected, got)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewEndpointsSourceApi_UpdatesAndMultipleEndpoints(t *testing.T) {
 | 
					func TestNewEndpointsSourceApi_UpdatesAndMultipleEndpoints(t *testing.T) {
 | 
				
			||||||
@@ -270,7 +240,7 @@ func TestInitialSync(t *testing.T) {
 | 
				
			|||||||
		watchResp: fakeEpsWatch,
 | 
							watchResp: fakeEpsWatch,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	svcConfig := NewServiceConfig()
 | 
						svcConfig := newServiceConfig(svcLW, time.Minute)
 | 
				
			||||||
	epsConfig := newEndpointsConfig(epsLW, time.Minute)
 | 
						epsConfig := newEndpointsConfig(epsLW, time.Minute)
 | 
				
			||||||
	svcHandler := newSvcHandler(t, []api.Service{*svc2, *svc1}, wg.Done)
 | 
						svcHandler := newSvcHandler(t, []api.Service{*svc2, *svc1}, wg.Done)
 | 
				
			||||||
	svcConfig.RegisterHandler(svcHandler)
 | 
						svcConfig.RegisterHandler(svcHandler)
 | 
				
			||||||
@@ -279,7 +249,7 @@ func TestInitialSync(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	stopCh := make(chan struct{})
 | 
						stopCh := make(chan struct{})
 | 
				
			||||||
	defer close(stopCh)
 | 
						defer close(stopCh)
 | 
				
			||||||
 | 
						go svcConfig.Run(stopCh)
 | 
				
			||||||
	go epsConfig.Run(stopCh)
 | 
						go epsConfig.Run(stopCh)
 | 
				
			||||||
	newSourceAPI(svcLW, time.Minute, svcConfig.Channel("one"), stopCh)
 | 
					 | 
				
			||||||
	wg.Wait()
 | 
						wg.Wait()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,15 +18,12 @@ package config
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/davecgh/go-spew/spew"
 | 
					 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/fields"
 | 
						"k8s.io/apimachinery/pkg/fields"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/labels"
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
					 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/client-go/tools/cache"
 | 
						"k8s.io/client-go/tools/cache"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
@@ -183,102 +180,101 @@ func (c *EndpointsConfig) dispatchUpdate() {
 | 
				
			|||||||
// ServiceConfig tracks a set of service configurations.
 | 
					// ServiceConfig tracks a set of service configurations.
 | 
				
			||||||
// It accepts "set", "add" and "remove" operations of services via channels, and invokes registered handlers on change.
 | 
					// It accepts "set", "add" and "remove" operations of services via channels, and invokes registered handlers on change.
 | 
				
			||||||
type ServiceConfig struct {
 | 
					type ServiceConfig struct {
 | 
				
			||||||
	mux     *config.Mux
 | 
						informer cache.Controller
 | 
				
			||||||
	bcaster *config.Broadcaster
 | 
						lister   listers.ServiceLister
 | 
				
			||||||
	store   *serviceStore
 | 
						handlers []ServiceConfigHandler
 | 
				
			||||||
 | 
						// updates channel is used to trigger registered handlers
 | 
				
			||||||
 | 
						updates chan struct{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewServiceConfig creates a new ServiceConfig.
 | 
					// NewServiceConfig creates a new ServiceConfig.
 | 
				
			||||||
// It immediately runs the created ServiceConfig.
 | 
					func NewServiceConfig(c cache.Getter, period time.Duration) *ServiceConfig {
 | 
				
			||||||
func NewServiceConfig() *ServiceConfig {
 | 
						servicesLW := cache.NewListWatchFromClient(c, "services", metav1.NamespaceAll, fields.Everything())
 | 
				
			||||||
	// The updates channel is used to send interrupts to the Services handler.
 | 
						return newServiceConfig(servicesLW, period)
 | 
				
			||||||
	// It's buffered because we never want to block for as long as there is a
 | 
					}
 | 
				
			||||||
	// pending interrupt, but don't want to drop them if the handler is doing
 | 
					
 | 
				
			||||||
	// work.
 | 
					func newServiceConfig(lw cache.ListerWatcher, period time.Duration) *ServiceConfig {
 | 
				
			||||||
	updates := make(chan struct{}, 1)
 | 
						result := &ServiceConfig{}
 | 
				
			||||||
	store := &serviceStore{updates: updates, services: make(map[string]map[types.NamespacedName]*api.Service)}
 | 
					
 | 
				
			||||||
	mux := config.NewMux(store)
 | 
						store, informer := cache.NewIndexerInformer(
 | 
				
			||||||
	bcaster := config.NewBroadcaster()
 | 
							lw,
 | 
				
			||||||
	go watchForUpdates(bcaster, store, updates)
 | 
							&api.Service{},
 | 
				
			||||||
	return &ServiceConfig{mux, bcaster, store}
 | 
							period,
 | 
				
			||||||
 | 
							cache.ResourceEventHandlerFuncs{
 | 
				
			||||||
 | 
								AddFunc:    result.handleAddService,
 | 
				
			||||||
 | 
								UpdateFunc: result.handleUpdateService,
 | 
				
			||||||
 | 
								DeleteFunc: result.handleDeleteService,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							cache.Indexers{},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						result.informer = informer
 | 
				
			||||||
 | 
						result.lister = listers.NewServiceLister(store)
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegisterHandler registers a handler which is called on every services change.
 | 
					// RegisterHandler registers a handler which is called on every services change.
 | 
				
			||||||
func (c *ServiceConfig) RegisterHandler(handler ServiceConfigHandler) {
 | 
					func (c *ServiceConfig) RegisterHandler(handler ServiceConfigHandler) {
 | 
				
			||||||
	c.bcaster.Add(config.ListenerFunc(func(instance interface{}) {
 | 
						c.handlers = append(c.handlers, handler)
 | 
				
			||||||
		glog.V(3).Infof("Calling handler.OnServiceUpdate()")
 | 
					 | 
				
			||||||
		handler.OnServiceUpdate(instance.([]api.Service))
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Channel returns a channel to which services updates should be delivered.
 | 
					func (c *ServiceConfig) Run(stopCh <-chan struct{}) {
 | 
				
			||||||
func (c *ServiceConfig) Channel(source string) chan ServiceUpdate {
 | 
						// The updates channel is used to send interrupts to the Services handler.
 | 
				
			||||||
	ch := c.mux.Channel(source)
 | 
						// It's buffered because we never want to block for as long as there is a
 | 
				
			||||||
	serviceCh := make(chan ServiceUpdate)
 | 
						// pending interrupt, but don't want to drop them if the handler is doing
 | 
				
			||||||
 | 
						// work.
 | 
				
			||||||
 | 
						c.updates = make(chan struct{}, 1)
 | 
				
			||||||
 | 
						go c.informer.Run(stopCh)
 | 
				
			||||||
 | 
						if !cache.WaitForCacheSync(stopCh, c.informer.HasSynced) {
 | 
				
			||||||
 | 
							utilruntime.HandleError(fmt.Errorf("service controller not synced"))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// We hanve synced informers. Now we can start delivering updates
 | 
				
			||||||
 | 
						// to the registered handler.
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		for update := range serviceCh {
 | 
							for range c.updates {
 | 
				
			||||||
			ch <- update
 | 
								services, err := c.lister.List(labels.Everything())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									glog.Errorf("Error while listing services from cache: %v", err)
 | 
				
			||||||
 | 
									// This will cause a retry (if there isnt' any other trigger in-flight).
 | 
				
			||||||
 | 
									c.dispatchUpdate()
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								svcs := make([]api.Service, 0, len(services))
 | 
				
			||||||
 | 
								for i := range services {
 | 
				
			||||||
 | 
									svcs = append(svcs, *services[i])
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for i := range c.handlers {
 | 
				
			||||||
 | 
									glog.V(3).Infof("Calling handler.OnServiceUpdate()")
 | 
				
			||||||
 | 
									c.handlers[i].OnServiceUpdate(svcs)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	return serviceCh
 | 
						// Close updates channel when stopCh is closed.
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							<-stopCh
 | 
				
			||||||
 | 
							close(c.updates)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Config returns list of all services from underlying store.
 | 
					func (c *ServiceConfig) handleAddService(_ interface{}) {
 | 
				
			||||||
func (c *ServiceConfig) Config() []api.Service {
 | 
						c.dispatchUpdate()
 | 
				
			||||||
	return c.store.MergedState().([]api.Service)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type serviceStore struct {
 | 
					func (c *ServiceConfig) handleUpdateService(_, _ interface{}) {
 | 
				
			||||||
	serviceLock sync.RWMutex
 | 
						c.dispatchUpdate()
 | 
				
			||||||
	services    map[string]map[types.NamespacedName]*api.Service
 | 
					 | 
				
			||||||
	synced      bool
 | 
					 | 
				
			||||||
	updates     chan<- struct{}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *serviceStore) Merge(source string, change interface{}) error {
 | 
					func (c *ServiceConfig) handleDeleteService(_ interface{}) {
 | 
				
			||||||
	s.serviceLock.Lock()
 | 
						c.dispatchUpdate()
 | 
				
			||||||
	services := s.services[source]
 | 
					}
 | 
				
			||||||
	if services == nil {
 | 
					
 | 
				
			||||||
		services = make(map[types.NamespacedName]*api.Service)
 | 
					func (c *ServiceConfig) dispatchUpdate() {
 | 
				
			||||||
	}
 | 
						select {
 | 
				
			||||||
	update := change.(ServiceUpdate)
 | 
						case c.updates <- struct{}{}:
 | 
				
			||||||
	switch update.Op {
 | 
					 | 
				
			||||||
	case ADD, UPDATE:
 | 
					 | 
				
			||||||
		glog.V(5).Infof("Adding new service from source %s : %s", source, spew.Sdump(update.Service))
 | 
					 | 
				
			||||||
		name := types.NamespacedName{Namespace: update.Service.Namespace, Name: update.Service.Name}
 | 
					 | 
				
			||||||
		services[name] = update.Service
 | 
					 | 
				
			||||||
	case REMOVE:
 | 
					 | 
				
			||||||
		glog.V(5).Infof("Removing a service %s", spew.Sdump(update.Service))
 | 
					 | 
				
			||||||
		name := types.NamespacedName{Namespace: update.Service.Namespace, Name: update.Service.Name}
 | 
					 | 
				
			||||||
		delete(services, name)
 | 
					 | 
				
			||||||
	case SYNCED:
 | 
					 | 
				
			||||||
		s.synced = true
 | 
					 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		glog.V(4).Infof("Received invalid update type: %s", spew.Sdump(update))
 | 
							glog.V(4).Infof("Service handler alread has a pending interrupt.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	s.services[source] = services
 | 
					 | 
				
			||||||
	synced := s.synced
 | 
					 | 
				
			||||||
	s.serviceLock.Unlock()
 | 
					 | 
				
			||||||
	if s.updates != nil && synced {
 | 
					 | 
				
			||||||
		select {
 | 
					 | 
				
			||||||
		case s.updates <- struct{}{}:
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			glog.V(4).Infof("Service handler already has a pending interrupt.")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *serviceStore) MergedState() interface{} {
 | 
					 | 
				
			||||||
	s.serviceLock.RLock()
 | 
					 | 
				
			||||||
	defer s.serviceLock.RUnlock()
 | 
					 | 
				
			||||||
	services := make([]api.Service, 0)
 | 
					 | 
				
			||||||
	for _, sourceServices := range s.services {
 | 
					 | 
				
			||||||
		for _, value := range sourceServices {
 | 
					 | 
				
			||||||
			services = append(services, *value)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return services
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// watchForUpdates invokes bcaster.Notify() with the latest version of an object
 | 
					// watchForUpdates invokes bcaster.Notify() with the latest version of an object
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -139,92 +139,89 @@ func CreateEndpointsUpdate(op Operation, endpoints *api.Endpoints) EndpointsUpda
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewServiceAddedAndNotified(t *testing.T) {
 | 
					func TestNewServiceAddedAndNotified(t *testing.T) {
 | 
				
			||||||
	config := NewServiceConfig()
 | 
						fakeWatch := watch.NewFake()
 | 
				
			||||||
	config.store.synced = true
 | 
						lw := fakeLW{
 | 
				
			||||||
	channel := config.Channel("one")
 | 
							listResp:  &api.ServiceList{Items: []api.Service{}},
 | 
				
			||||||
 | 
							watchResp: fakeWatch,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						stopCh := make(chan struct{})
 | 
				
			||||||
 | 
						defer close(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config := newServiceConfig(lw, time.Minute)
 | 
				
			||||||
	handler := NewServiceHandlerMock()
 | 
						handler := NewServiceHandlerMock()
 | 
				
			||||||
	config.RegisterHandler(handler)
 | 
						config.RegisterHandler(handler)
 | 
				
			||||||
	serviceUpdate := CreateServiceUpdate(ADD, &api.Service{
 | 
						go config.Run(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						service := &api.Service{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
							ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
							Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
				
			||||||
	})
 | 
						}
 | 
				
			||||||
	channel <- serviceUpdate
 | 
						fakeWatch.Add(service)
 | 
				
			||||||
	handler.ValidateServices(t, []api.Service{*serviceUpdate.Service})
 | 
						handler.ValidateServices(t, []api.Service{*service})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestServiceAddedRemovedSetAndNotified(t *testing.T) {
 | 
					func TestServiceAddedRemovedSetAndNotified(t *testing.T) {
 | 
				
			||||||
	config := NewServiceConfig()
 | 
						fakeWatch := watch.NewFake()
 | 
				
			||||||
	config.store.synced = true
 | 
						lw := fakeLW{
 | 
				
			||||||
	channel := config.Channel("one")
 | 
							listResp:  &api.ServiceList{Items: []api.Service{}},
 | 
				
			||||||
	handler := NewServiceHandlerMock()
 | 
							watchResp: fakeWatch,
 | 
				
			||||||
	config.RegisterHandler(handler)
 | 
					 | 
				
			||||||
	serviceUpdate := CreateServiceUpdate(ADD, &api.Service{
 | 
					 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
					 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	channel <- serviceUpdate
 | 
					 | 
				
			||||||
	handler.ValidateServices(t, []api.Service{*serviceUpdate.Service})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	serviceUpdate2 := CreateServiceUpdate(ADD, &api.Service{
 | 
					 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"},
 | 
					 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 20}}},
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	channel <- serviceUpdate2
 | 
					 | 
				
			||||||
	services := []api.Service{*serviceUpdate2.Service, *serviceUpdate.Service}
 | 
					 | 
				
			||||||
	handler.ValidateServices(t, services)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	serviceUpdate3 := CreateServiceUpdate(REMOVE, &api.Service{
 | 
					 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	channel <- serviceUpdate3
 | 
					 | 
				
			||||||
	services = []api.Service{*serviceUpdate2.Service}
 | 
					 | 
				
			||||||
	handler.ValidateServices(t, services)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestNewMultipleSourcesServicesAddedAndNotified(t *testing.T) {
 | 
					 | 
				
			||||||
	config := NewServiceConfig()
 | 
					 | 
				
			||||||
	config.store.synced = true
 | 
					 | 
				
			||||||
	channelOne := config.Channel("one")
 | 
					 | 
				
			||||||
	channelTwo := config.Channel("two")
 | 
					 | 
				
			||||||
	if channelOne == channelTwo {
 | 
					 | 
				
			||||||
		t.Error("Same channel handed back for one and two")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						stopCh := make(chan struct{})
 | 
				
			||||||
 | 
						defer close(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config := newServiceConfig(lw, time.Minute)
 | 
				
			||||||
	handler := NewServiceHandlerMock()
 | 
						handler := NewServiceHandlerMock()
 | 
				
			||||||
	config.RegisterHandler(handler)
 | 
						config.RegisterHandler(handler)
 | 
				
			||||||
	serviceUpdate1 := CreateServiceUpdate(ADD, &api.Service{
 | 
						go config.Run(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						service1 := &api.Service{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
							ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
							Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
				
			||||||
	})
 | 
						}
 | 
				
			||||||
	serviceUpdate2 := CreateServiceUpdate(ADD, &api.Service{
 | 
						fakeWatch.Add(service1)
 | 
				
			||||||
 | 
						handler.ValidateServices(t, []api.Service{*service1})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						service2 := &api.Service{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"},
 | 
							ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"},
 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 20}}},
 | 
							Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 20}}},
 | 
				
			||||||
	})
 | 
						}
 | 
				
			||||||
	channelOne <- serviceUpdate1
 | 
						fakeWatch.Add(service2)
 | 
				
			||||||
	channelTwo <- serviceUpdate2
 | 
						services := []api.Service{*service2, *service1}
 | 
				
			||||||
	services := []api.Service{*serviceUpdate2.Service, *serviceUpdate1.Service}
 | 
						handler.ValidateServices(t, services)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fakeWatch.Delete(service1)
 | 
				
			||||||
 | 
						services = []api.Service{*service2}
 | 
				
			||||||
	handler.ValidateServices(t, services)
 | 
						handler.ValidateServices(t, services)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewMultipleSourcesServicesMultipleHandlersAddedAndNotified(t *testing.T) {
 | 
					func TestNewServicesMultipleHandlersAddedAndNotified(t *testing.T) {
 | 
				
			||||||
	config := NewServiceConfig()
 | 
						fakeWatch := watch.NewFake()
 | 
				
			||||||
	config.store.synced = true
 | 
						lw := fakeLW{
 | 
				
			||||||
	channelOne := config.Channel("one")
 | 
							listResp:  &api.ServiceList{Items: []api.Service{}},
 | 
				
			||||||
	channelTwo := config.Channel("two")
 | 
							watchResp: fakeWatch,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						stopCh := make(chan struct{})
 | 
				
			||||||
 | 
						defer close(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config := newServiceConfig(lw, time.Minute)
 | 
				
			||||||
	handler := NewServiceHandlerMock()
 | 
						handler := NewServiceHandlerMock()
 | 
				
			||||||
	handler2 := NewServiceHandlerMock()
 | 
						handler2 := NewServiceHandlerMock()
 | 
				
			||||||
	config.RegisterHandler(handler)
 | 
						config.RegisterHandler(handler)
 | 
				
			||||||
	config.RegisterHandler(handler2)
 | 
						config.RegisterHandler(handler2)
 | 
				
			||||||
	serviceUpdate1 := CreateServiceUpdate(ADD, &api.Service{
 | 
						go config.Run(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						service1 := &api.Service{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
							ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"},
 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
							Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}},
 | 
				
			||||||
	})
 | 
						}
 | 
				
			||||||
	serviceUpdate2 := CreateServiceUpdate(ADD, &api.Service{
 | 
						service2 := &api.Service{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"},
 | 
							ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"},
 | 
				
			||||||
		Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 20}}},
 | 
							Spec:       api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 20}}},
 | 
				
			||||||
	})
 | 
						}
 | 
				
			||||||
	channelOne <- serviceUpdate1
 | 
						fakeWatch.Add(service1)
 | 
				
			||||||
	channelTwo <- serviceUpdate2
 | 
						fakeWatch.Add(service2)
 | 
				
			||||||
	services := []api.Service{*serviceUpdate2.Service, *serviceUpdate1.Service}
 | 
					
 | 
				
			||||||
 | 
						services := []api.Service{*service2, *service1}
 | 
				
			||||||
	handler.ValidateServices(t, services)
 | 
						handler.ValidateServices(t, services)
 | 
				
			||||||
	handler2.ValidateServices(t, services)
 | 
						handler2.ValidateServices(t, services)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user