func New(c *config.Config, fw framework.Framework, ps podschedulers.PodScheduler, client *client.Client, recorder record.EventRecorder, terminate <-chan struct{}, mux *http.ServeMux, lw *cache.ListWatch) scheduler.Scheduler { core := &sched{ framework: fw, taskRegistry: podtask.NewInMemoryRegistry(), } // Watch and queue pods that need scheduling. podUpdatesBypass := make(chan queue.Entry, c.UpdatesBacklog) podUpdates := &podStoreAdapter{queue.NewHistorical(podUpdatesBypass)} reflector := cache.NewReflector(lw, &api.Pod{}, podUpdates, 0) q := queuer.New(queue.NewDelayFIFO(), podUpdates) algorithm := algorithm.New(core, podUpdates, ps) podDeleter := deleter.New(core, q) core.podReconciler = podreconciler.New(core, client, q, podDeleter) bo := backoff.New(c.InitialPodBackoff.Duration, c.MaxPodBackoff.Duration) newBC := func(podKey string) queue.BreakChan { return queue.BreakChan(core.Offers().Listen(podKey, func(offer *mesos.Offer) bool { core.Lock() defer core.Unlock() switch task, state := core.Tasks().ForPod(podKey); state { case podtask.StatePending: // Assess fitness of pod with the current offer. The scheduler normally // "backs off" when it can't find an offer that matches up with a pod. // The backoff period for a pod can terminate sooner if an offer becomes // available that matches up. return !task.Has(podtask.Launched) && ps.FitPredicate()(task, offer, nil) default: // no point in continuing to check for matching offers return true } })) } errorHandler := errorhandler.New(core, bo, q, newBC) binder := binder.New(core) startLatch := make(chan struct{}) runtime.On(startLatch, func() { reflector.Run() // TODO(jdef) should listen for termination podDeleter.Run(podUpdatesBypass, terminate) q.Run(terminate) q.InstallDebugHandlers(mux) podtask.InstallDebugHandlers(core.Tasks(), mux) }) core.controller = controller.New(client, algorithm, recorder, q.Yield, errorHandler.Error, binder, startLatch) return core }
func TestDeleteOne_Running(t *testing.T) { assert := assert.New(t) obj := &types.MockScheduler{} reg := podtask.NewInMemoryRegistry() obj.On("Tasks").Return(reg) pod := &queuer.Pod{Pod: &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", UID: "foo0", Namespace: api.NamespaceDefault, }}} task, err := podtask.New( api.NewDefaultContext(), podtask.Config{ ID: "bar", Prototype: &mesosproto.ExecutorInfo{}, HostPortStrategy: hostport.StrategyWildcard, }, pod.Pod, ) if err != nil { t.Fatalf("unexpected error: %v", err) } task, err = reg.Register(task) if err != nil { t.Fatalf("unexpected error: %v", err) } task.Set(podtask.Launched) err = reg.Update(task) if err != nil { t.Fatalf("unexpected error: %v", err) } // preconditions q := queue.NewDelayFIFO() qr := queuer.New(q, nil) q.Add(pod, queue.ReplaceExisting) assert.Equal(1, len(q.List())) _, found := q.Get("default/foo") assert.True(found) obj.On("KillTask", task.ID).Return(nil) // exec & post conditions d := New(obj, qr) err = d.DeleteOne(pod) assert.Nil(err) _, found = q.Get("foo0") assert.False(found) assert.Equal(0, len(q.List())) obj.AssertExpectations(t) }
func TestDeleteOne_PendingPod(t *testing.T) { assert := assert.New(t) obj := &types.MockScheduler{} reg := podtask.NewInMemoryRegistry() obj.On("Tasks").Return(reg) pod := &queuer.Pod{Pod: &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", UID: "foo0", Namespace: api.NamespaceDefault, }}} task, err := podtask.New( api.NewDefaultContext(), "bar", pod.Pod, &mesosproto.ExecutorInfo{}, nil, nil, ) if err != nil { t.Fatalf("failed to create task: %v", err) } _, err = reg.Register(task) if err != nil { t.Fatalf("failed to register task: %v", err) } // preconditions q := queue.NewDelayFIFO() qr := queuer.New(q, nil) q.Add(pod, queue.ReplaceExisting) assert.Equal(1, len(q.List())) _, found := q.Get("default/foo") assert.True(found) // exec & post conditions d := New(obj, qr) err = d.DeleteOne(pod) assert.Nil(err) _, found = q.Get("foo0") assert.False(found) assert.Equal(0, len(q.List())) obj.AssertExpectations(t) }
func TestDeleteOne_NonexistentPod(t *testing.T) { assert := assert.New(t) obj := &types.MockScheduler{} reg := podtask.NewInMemoryRegistry() obj.On("Tasks").Return(reg) q := queue.NewDelayFIFO() qr := queuer.New(q, nil) assert.Equal(0, len(q.List())) d := New(obj, qr) pod := &queuer.Pod{Pod: &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }}} err := d.DeleteOne(pod) assert.Equal(err, errors.NoSuchPodErr) obj.AssertExpectations(t) }
func TestDeleteOne_badPodNaming(t *testing.T) { assert := assert.New(t) obj := &types.MockScheduler{} pod := &queuer.Pod{Pod: &api.Pod{}} q := queue.NewDelayFIFO() qr := queuer.New(q, nil) d := New(obj, qr) err := d.DeleteOne(pod) assert.NotNil(err) pod.Pod.ObjectMeta.Name = "foo" err = d.DeleteOne(pod) assert.NotNil(err) pod.Pod.ObjectMeta.Name = "" pod.Pod.ObjectMeta.Namespace = "bar" err = d.DeleteOne(pod) assert.NotNil(err) obj.AssertExpectations(t) }