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
}
Example #2
0
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)
}