// newLoadBalancerController creates a new controller from the given config. func newLoadBalancerController(cfg *loadBalancerConfig, kubeClient *client.Client, namespace string) *loadBalancerController { lbc := loadBalancerController{ cfg: cfg, client: kubeClient, queue: workqueue.New(), reloadRateLimiter: util.NewTokenBucketRateLimiter( reloadQPS, int(reloadQPS)), targetService: *targetService, forwardServices: *forwardServices, httpPort: *httpPort, tcpServices: map[string]int{}, } for _, service := range strings.Split(*tcpServices, ",") { portSplit := strings.Split(service, ":") if len(portSplit) != 2 { glog.Errorf("Ignoring misconfigured TCP service %v", service) continue } if port, err := strconv.Atoi(portSplit[1]); err != nil { glog.Errorf("Ignoring misconfigured TCP service %v: %v", service, err) continue } else { lbc.tcpServices[portSplit[0]] = port } } enqueue := func(obj interface{}) { key, err := keyFunc(obj) if err != nil { glog.Infof("Couldn't get key for object %+v: %v", obj, err) return } lbc.queue.Add(key) } eventHandlers := framework.ResourceEventHandlerFuncs{ AddFunc: enqueue, DeleteFunc: enqueue, UpdateFunc: func(old, cur interface{}) { if !reflect.DeepEqual(old, cur) { enqueue(cur) } }, } lbc.svcLister.Store, lbc.svcController = framework.NewInformer( cache.NewListWatchFromClient( lbc.client, "services", namespace, fields.Everything()), &api.Service{}, resyncPeriod, eventHandlers) lbc.epLister.Store, lbc.epController = framework.NewInformer( cache.NewListWatchFromClient( lbc.client, "endpoints", namespace, fields.Everything()), &api.Endpoints{}, resyncPeriod, eventHandlers) return &lbc }
func TestLen(t *testing.T) { q := workqueue.New() q.Add("foo") if e, a := 1, q.Len(); e != a { t.Errorf("Expected %v, got %v", e, a) } q.Add("bar") if e, a := 2, q.Len(); e != a { t.Errorf("Expected %v, got %v", e, a) } q.Add("foo") // should not increase the queue length. if e, a := 2, q.Len(); e != a { t.Errorf("Expected %v, got %v", e, a) } }
func TestBasic(t *testing.T) { // If something is seriously wrong this test will never complete. q := workqueue.New() // Start producers const producers = 50 producerWG := sync.WaitGroup{} producerWG.Add(producers) for i := 0; i < producers; i++ { go func(i int) { defer producerWG.Done() for j := 0; j < 50; j++ { q.Add(i) time.Sleep(time.Millisecond) } }(i) } // Start consumers const consumers = 10 consumerWG := sync.WaitGroup{} consumerWG.Add(consumers) for i := 0; i < consumers; i++ { go func(i int) { defer consumerWG.Done() for { item, quit := q.Get() if item == "added after shutdown!" { t.Errorf("Got an item added after shutdown.") } if quit { return } t.Logf("Worker %v: begin processing %v", i, item) time.Sleep(3 * time.Millisecond) t.Logf("Worker %v: done processing %v", i, item) q.Done(item) } }(i) } producerWG.Wait() q.ShutDown() q.Add("added after shutdown!") consumerWG.Wait() }
// NewEndpointController returns a new *EndpointController. func NewEndpointController(client *client.Client) *EndpointController { e := &EndpointController{ client: client, queue: workqueue.New(), } e.serviceStore.Store, e.serviceController = framework.NewInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return e.client.Services(api.NamespaceAll).List(labels.Everything()) }, WatchFunc: func(rv string) (watch.Interface, error) { return e.client.Services(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), rv) }, }, &api.Service{}, FullServiceResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: e.enqueueService, UpdateFunc: func(old, cur interface{}) { e.enqueueService(cur) }, DeleteFunc: e.enqueueService, }, ) e.podStore.Store, e.podController = framework.NewInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return e.client.Pods(api.NamespaceAll).List(labels.Everything(), fields.Everything()) }, WatchFunc: func(rv string) (watch.Interface, error) { return e.client.Pods(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), rv) }, }, &api.Pod{}, PodRelistPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: e.addPod, UpdateFunc: e.updatePod, DeleteFunc: e.deletePod, }, ) return e }
func TestAddWhileProcessing(t *testing.T) { q := workqueue.New() // Start producers const producers = 50 producerWG := sync.WaitGroup{} producerWG.Add(producers) for i := 0; i < producers; i++ { go func(i int) { defer producerWG.Done() q.Add(i) }(i) } // Start consumers const consumers = 10 consumerWG := sync.WaitGroup{} consumerWG.Add(consumers) for i := 0; i < consumers; i++ { go func(i int) { defer consumerWG.Done() // Every worker will re-add every item up to two times. // This tests the dirty-while-processing case. counters := map[interface{}]int{} for { item, quit := q.Get() if quit { return } counters[item]++ if counters[item] < 2 { q.Add(item) } q.Done(item) } }(i) } producerWG.Wait() q.ShutDown() consumerWG.Wait() }
// NewReplicationManager creates a new ReplicationManager. func NewReplicationManager(kubeClient client.Interface, burstReplicas int) *ReplicationManager { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(kubeClient.Events("")) rm := &ReplicationManager{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "replication-controller"}), }, burstReplicas: burstReplicas, expectations: controller.NewControllerExpectations(), queue: workqueue.New(), } rm.rcStore.Store, rm.rcController = framework.NewInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return rm.kubeClient.ReplicationControllers(api.NamespaceAll).List(labels.Everything()) }, WatchFunc: func(rv string) (watch.Interface, error) { return rm.kubeClient.ReplicationControllers(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), rv) }, }, &api.ReplicationController{}, FullControllerResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: rm.enqueueController, UpdateFunc: func(old, cur interface{}) { // We only really need to do this when spec changes, but for correctness it is safer to // periodically double check. It is overkill for 2 reasons: // 1. Status.Replica updates will cause a sync // 2. Every 30s we will get a full resync (this will happen anyway every 5 minutes when pods relist) // However, it shouldn't be that bad as rcs that haven't met expectations won't sync, and all // the listing is done using local stores. oldRC := old.(*api.ReplicationController) curRC := cur.(*api.ReplicationController) if oldRC.Status.Replicas != curRC.Status.Replicas { glog.V(4).Infof("Observed updated replica count for rc: %v, %d->%d", curRC.Name, oldRC.Status.Replicas, curRC.Status.Replicas) } rm.enqueueController(cur) }, // This will enter the sync loop and no-op, becuase the controller has been deleted from the store. // Note that deleting a controller immediately after scaling it to 0 will not work. The recommended // way of achieving this is by performing a `stop` operation on the controller. DeleteFunc: rm.enqueueController, }, ) rm.podStore.Store, rm.podController = framework.NewInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return rm.kubeClient.Pods(api.NamespaceAll).List(labels.Everything(), fields.Everything()) }, WatchFunc: func(rv string) (watch.Interface, error) { return rm.kubeClient.Pods(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), rv) }, }, &api.Pod{}, PodRelistPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: rm.addPod, // This invokes the rc for every pod change, eg: host assignment. Though this might seem like overkill // the most frequent pod update is status, and the associated rc will only list from local storage, so // it should be ok. UpdateFunc: rm.updatePod, DeleteFunc: rm.deletePod, }, ) rm.syncHandler = rm.syncReplicationController rm.podStoreSynced = rm.podController.HasSynced return rm }