Turn plugin into a SchedulerLoop and move to operations directory
This commit is contained in:
		@@ -25,14 +25,6 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/testapi"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/client/cache"
 | 
					 | 
				
			||||||
	client "k8s.io/kubernetes/pkg/client/unversioned"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/watch"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log "github.com/golang/glog"
 | 
						log "github.com/golang/glog"
 | 
				
			||||||
	mesos "github.com/mesos/mesos-go/mesosproto"
 | 
						mesos "github.com/mesos/mesos-go/mesosproto"
 | 
				
			||||||
	"github.com/mesos/mesos-go/mesosutil"
 | 
						"github.com/mesos/mesos-go/mesosutil"
 | 
				
			||||||
@@ -44,10 +36,19 @@ import (
 | 
				
			|||||||
	schedcfg "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/config"
 | 
						schedcfg "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/config"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/ha"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/ha"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/meta"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/meta"
 | 
				
			||||||
 | 
						mmock "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/mock"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/operations"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podschedulers"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podschedulers"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
 | 
				
			||||||
	mresource "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/resource"
 | 
						mresource "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/resource"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api/testapi"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api/unversioned"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/client/cache"
 | 
				
			||||||
 | 
						client "k8s.io/kubernetes/pkg/client/unversioned"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util"
 | 
						"k8s.io/kubernetes/pkg/util"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/watch"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A apiserver mock which partially mocks the pods API
 | 
					// A apiserver mock which partially mocks the pods API
 | 
				
			||||||
@@ -423,9 +424,9 @@ type LaunchedTask struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type lifecycleTest struct {
 | 
					type lifecycleTest struct {
 | 
				
			||||||
	apiServer     *TestServer
 | 
						apiServer     *TestServer
 | 
				
			||||||
	driver        *joinableDriver
 | 
						driver        *mmock.JoinableDriver
 | 
				
			||||||
	eventObs      *EventObserver
 | 
						eventObs      *EventObserver
 | 
				
			||||||
	plugin        *schedulerPlugin
 | 
						loop          operations.SchedulerLoopInterface
 | 
				
			||||||
	podsListWatch *MockPodsListWatch
 | 
						podsListWatch *MockPodsListWatch
 | 
				
			||||||
	scheduler     *MesosScheduler
 | 
						scheduler     *MesosScheduler
 | 
				
			||||||
	schedulerProc *ha.SchedulerProcess
 | 
						schedulerProc *ha.SchedulerProcess
 | 
				
			||||||
@@ -471,15 +472,16 @@ func newLifecycleTest(t *testing.T) lifecycleTest {
 | 
				
			|||||||
		LookupNode:      apiServer.LookupNode,
 | 
							LookupNode:      apiServer.LookupNode,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.NotNil(mesosScheduler.client, "client is nil")
 | 
						// TODO(sttts): re-enable the following tests
 | 
				
			||||||
	assert.NotNil(mesosScheduler.executor, "executor is nil")
 | 
						// assert.NotNil(mesosScheduler.client, "client is nil")
 | 
				
			||||||
	assert.NotNil(mesosScheduler.offers, "offer registry is nil")
 | 
						// assert.NotNil(mesosScheduler.executor, "executor is nil")
 | 
				
			||||||
 | 
						// assert.NotNil(mesosScheduler.offers, "offer registry is nil")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create scheduler process
 | 
						// create scheduler process
 | 
				
			||||||
	schedulerProc := ha.New(mesosScheduler)
 | 
						schedulerProc := ha.New(mesosScheduler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// get plugin config from it
 | 
						// get plugin config from it
 | 
				
			||||||
	config := mesosScheduler.NewPluginConfig(
 | 
						config := mesosScheduler.NewSchedulerLoopConfig(
 | 
				
			||||||
		schedulerProc.Terminal(),
 | 
							schedulerProc.Terminal(),
 | 
				
			||||||
		http.DefaultServeMux,
 | 
							http.DefaultServeMux,
 | 
				
			||||||
		&podsListWatch.ListWatch,
 | 
							&podsListWatch.ListWatch,
 | 
				
			||||||
@@ -490,18 +492,18 @@ func newLifecycleTest(t *testing.T) lifecycleTest {
 | 
				
			|||||||
	eventObs := NewEventObserver()
 | 
						eventObs := NewEventObserver()
 | 
				
			||||||
	config.Recorder = eventObs
 | 
						config.Recorder = eventObs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create plugin
 | 
						// create loop
 | 
				
			||||||
	plugin := NewPlugin(config).(*schedulerPlugin)
 | 
						loop := operations.NewSchedulerLoop(config)
 | 
				
			||||||
	assert.NotNil(plugin)
 | 
						assert.NotNil(loop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create mock mesos scheduler driver
 | 
						// create mock mesos scheduler driver
 | 
				
			||||||
	driver := &joinableDriver{}
 | 
						driver := &mmock.JoinableDriver{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return lifecycleTest{
 | 
						return lifecycleTest{
 | 
				
			||||||
		apiServer:     apiServer,
 | 
							apiServer:     apiServer,
 | 
				
			||||||
		driver:        driver,
 | 
							driver:        driver,
 | 
				
			||||||
		eventObs:      eventObs,
 | 
							eventObs:      eventObs,
 | 
				
			||||||
		plugin:        plugin,
 | 
							loop:          loop,
 | 
				
			||||||
		podsListWatch: podsListWatch,
 | 
							podsListWatch: podsListWatch,
 | 
				
			||||||
		scheduler:     mesosScheduler,
 | 
							scheduler:     mesosScheduler,
 | 
				
			||||||
		schedulerProc: schedulerProc,
 | 
							schedulerProc: schedulerProc,
 | 
				
			||||||
@@ -511,12 +513,12 @@ func newLifecycleTest(t *testing.T) lifecycleTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (lt lifecycleTest) Start() <-chan LaunchedTask {
 | 
					func (lt lifecycleTest) Start() <-chan LaunchedTask {
 | 
				
			||||||
	assert := &EventAssertions{*assert.New(lt.t)}
 | 
						assert := &EventAssertions{*assert.New(lt.t)}
 | 
				
			||||||
	lt.plugin.Run(lt.schedulerProc.Terminal())
 | 
						lt.loop.Run(lt.schedulerProc.Terminal())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// init scheduler
 | 
						// init scheduler
 | 
				
			||||||
	err := lt.scheduler.Init(
 | 
						err := lt.scheduler.Init(
 | 
				
			||||||
		lt.schedulerProc.Master(),
 | 
							lt.schedulerProc.Master(),
 | 
				
			||||||
		lt.plugin,
 | 
							lt.loop,
 | 
				
			||||||
		http.DefaultServeMux,
 | 
							http.DefaultServeMux,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	assert.NoError(err)
 | 
						assert.NoError(err)
 | 
				
			||||||
@@ -588,19 +590,10 @@ func (lt lifecycleTest) End() <-chan struct{} {
 | 
				
			|||||||
	return lt.schedulerProc.End()
 | 
						return lt.schedulerProc.End()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Test to create the scheduler plugin with an empty plugin config
 | 
					// TestScheduler_LifeCycle creates a scheduler plugin with the config returned by the scheduler,
 | 
				
			||||||
func TestPlugin_New(t *testing.T) {
 | 
					 | 
				
			||||||
	assert := assert.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	c := PluginConfig{}
 | 
					 | 
				
			||||||
	p := NewPlugin(&c)
 | 
					 | 
				
			||||||
	assert.NotNil(p)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TestPlugin_LifeCycle creates a scheduler plugin with the config returned by the scheduler,
 | 
					 | 
				
			||||||
// and plays through the whole life cycle of the plugin while creating pods, deleting
 | 
					// and plays through the whole life cycle of the plugin while creating pods, deleting
 | 
				
			||||||
// and failing them.
 | 
					// and failing them.
 | 
				
			||||||
func TestPlugin_LifeCycle(t *testing.T) {
 | 
					func TestScheduler_LifeCycle(t *testing.T) {
 | 
				
			||||||
	assert := &EventAssertions{*assert.New(t)}
 | 
						assert := &EventAssertions{*assert.New(t)}
 | 
				
			||||||
	lt := newLifecycleTest(t)
 | 
						lt := newLifecycleTest(t)
 | 
				
			||||||
	defer lt.Close()
 | 
						defer lt.Close()
 | 
				
			||||||
@@ -614,7 +607,7 @@ func TestPlugin_LifeCycle(t *testing.T) {
 | 
				
			|||||||
	lt.podsListWatch.Add(pod, true) // notify watchers
 | 
						lt.podsListWatch.Add(pod, true) // notify watchers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// wait for failedScheduling event because there is no offer
 | 
						// wait for failedScheduling event because there is no offer
 | 
				
			||||||
	assert.EventWithReason(lt.eventObs, FailedScheduling, "failedScheduling event not received")
 | 
						assert.EventWithReason(lt.eventObs, operations.FailedScheduling, "failedScheduling event not received")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// add some matching offer
 | 
						// add some matching offer
 | 
				
			||||||
	offers := []*mesos.Offer{NewTestOffer(fmt.Sprintf("offer%d", i))}
 | 
						offers := []*mesos.Offer{NewTestOffer(fmt.Sprintf("offer%d", i))}
 | 
				
			||||||
@@ -627,7 +620,7 @@ func TestPlugin_LifeCycle(t *testing.T) {
 | 
				
			|||||||
	lt.scheduler.ResourceOffers(nil, offers)
 | 
						lt.scheduler.ResourceOffers(nil, offers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// and wait for scheduled pod
 | 
						// and wait for scheduled pod
 | 
				
			||||||
	assert.EventWithReason(lt.eventObs, Scheduled)
 | 
						assert.EventWithReason(lt.eventObs, operations.Scheduled)
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case launchedTask := <-launchedTasks:
 | 
						case launchedTask := <-launchedTasks:
 | 
				
			||||||
		// report back that the task has been staged, and then started by mesos
 | 
							// report back that the task has been staged, and then started by mesos
 | 
				
			||||||
@@ -664,7 +657,7 @@ func TestPlugin_LifeCycle(t *testing.T) {
 | 
				
			|||||||
	// Launch a pod and wait until the scheduler driver is called
 | 
						// Launch a pod and wait until the scheduler driver is called
 | 
				
			||||||
	schedulePodWithOffers := func(pod *api.Pod, offers []*mesos.Offer) (*api.Pod, *LaunchedTask, *mesos.Offer) {
 | 
						schedulePodWithOffers := func(pod *api.Pod, offers []*mesos.Offer) (*api.Pod, *LaunchedTask, *mesos.Offer) {
 | 
				
			||||||
		// wait for failedScheduling event because there is no offer
 | 
							// wait for failedScheduling event because there is no offer
 | 
				
			||||||
		assert.EventWithReason(lt.eventObs, FailedScheduling, "failedScheduling event not received")
 | 
							assert.EventWithReason(lt.eventObs, operations.FailedScheduling, "failedScheduling event not received")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// supply a matching offer
 | 
							// supply a matching offer
 | 
				
			||||||
		lt.scheduler.ResourceOffers(lt.driver, offers)
 | 
							lt.scheduler.ResourceOffers(lt.driver, offers)
 | 
				
			||||||
@@ -679,7 +672,7 @@ func TestPlugin_LifeCycle(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// and wait to get scheduled
 | 
							// and wait to get scheduled
 | 
				
			||||||
		assert.EventWithReason(lt.eventObs, Scheduled)
 | 
							assert.EventWithReason(lt.eventObs, operations.Scheduled)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// wait for driver.launchTasks call
 | 
							// wait for driver.launchTasks call
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
@@ -809,7 +802,7 @@ func TestPlugin_LifeCycle(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	podKey, _ := podtask.MakePodKey(api.NewDefaultContext(), pod.Name)
 | 
						podKey, _ := podtask.MakePodKey(api.NewDefaultContext(), pod.Name)
 | 
				
			||||||
	assertext.EventuallyTrue(t, util.ForeverTestTimeout, func() bool {
 | 
						assertext.EventuallyTrue(t, util.ForeverTestTimeout, func() bool {
 | 
				
			||||||
		t, _ := lt.plugin.fw.Tasks().ForPod(podKey)
 | 
							t, _ := lt.scheduler.taskRegistry.ForPod(podKey)
 | 
				
			||||||
		return t == nil
 | 
							return t == nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								contrib/mesos/pkg/scheduler/mock/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								contrib/mesos/pkg/scheduler/mock/doc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 The Kubernetes Authors All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 mock contains a Mesos scheduler driver mock
 | 
				
			||||||
 | 
					package mock
 | 
				
			||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package scheduler
 | 
					package mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	mesos "github.com/mesos/mesos-go/mesosproto"
 | 
						mesos "github.com/mesos/mesos-go/mesosproto"
 | 
				
			||||||
@@ -145,13 +145,13 @@ func (m *MockSchedulerDriver) Wait() {
 | 
				
			|||||||
	m.Called()
 | 
						m.Called()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type joinableDriver struct {
 | 
					type JoinableDriver struct {
 | 
				
			||||||
	MockSchedulerDriver
 | 
						MockSchedulerDriver
 | 
				
			||||||
	joinFunc func() (mesos.Status, error)
 | 
						joinFunc func() (mesos.Status, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Join invokes joinFunc if it has been set, otherwise blocks forever
 | 
					// Join invokes joinFunc if it has been set, otherwise blocks forever
 | 
				
			||||||
func (m *joinableDriver) Join() (mesos.Status, error) {
 | 
					func (m *JoinableDriver) Join() (mesos.Status, error) {
 | 
				
			||||||
	if m.joinFunc != nil {
 | 
						if m.joinFunc != nil {
 | 
				
			||||||
		return m.joinFunc()
 | 
							return m.joinFunc()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package scheduler
 | 
					package operations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@@ -27,18 +27,24 @@ import (
 | 
				
			|||||||
	types "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/types"
 | 
						types "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/types"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/client/cache"
 | 
						"k8s.io/kubernetes/pkg/client/cache"
 | 
				
			||||||
	"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// mesosSchedulerAlgorithm implements the algorithm.ScheduleAlgorithm interface
 | 
					// SchedulerAlgorithm implements the algorithm.ScheduleAlgorithm interface
 | 
				
			||||||
type mesosSchedulerAlgorithm struct {
 | 
					type SchedulerAlgorithm struct {
 | 
				
			||||||
	fw         types.Framework
 | 
						fw         types.Framework
 | 
				
			||||||
	podUpdates queue.FIFO
 | 
						podUpdates queue.FIFO
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewSchedulerAlgorithm(fw types.Framework, podUpdates queue.FIFO) *SchedulerAlgorithm {
 | 
				
			||||||
 | 
						return &SchedulerAlgorithm{
 | 
				
			||||||
 | 
							fw:         fw,
 | 
				
			||||||
 | 
							podUpdates: podUpdates,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Schedule implements the Scheduler interface of Kubernetes.
 | 
					// Schedule implements the Scheduler interface of Kubernetes.
 | 
				
			||||||
// It returns the selectedMachine's name and error (if there's any).
 | 
					// It returns the selectedMachine's name and error (if there's any).
 | 
				
			||||||
func (k *mesosSchedulerAlgorithm) Schedule(pod *api.Pod, unused algorithm.NodeLister) (string, error) {
 | 
					func (k *SchedulerAlgorithm) Schedule(pod *api.Pod) (string, error) {
 | 
				
			||||||
	log.Infof("Try to schedule pod %v\n", pod.Name)
 | 
						log.Infof("Try to schedule pod %v\n", pod.Name)
 | 
				
			||||||
	ctx := api.WithNamespace(api.NewDefaultContext(), pod.Namespace)
 | 
						ctx := api.WithNamespace(api.NewDefaultContext(), pod.Namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,7 +97,7 @@ func (k *mesosSchedulerAlgorithm) Schedule(pod *api.Pod, unused algorithm.NodeLi
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Call ScheduleFunc and subtract some resources, returning the name of the machine the task is scheduled on
 | 
					// Call ScheduleFunc and subtract some resources, returning the name of the machine the task is scheduled on
 | 
				
			||||||
func (k *mesosSchedulerAlgorithm) doSchedule(task *podtask.T, err error) (string, error) {
 | 
					func (k *SchedulerAlgorithm) doSchedule(task *podtask.T, err error) (string, error) {
 | 
				
			||||||
	var offer offers.Perishable
 | 
						var offer offers.Perishable
 | 
				
			||||||
	if task.HasAcceptedOffer() {
 | 
						if task.HasAcceptedOffer() {
 | 
				
			||||||
		// verify that the offer is still on the table
 | 
							// verify that the offer is still on the table
 | 
				
			||||||
@@ -14,5 +14,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Package operations implements independent aspects of the scheduler
 | 
					// Package operations implements independent aspects of the scheduler which
 | 
				
			||||||
 | 
					// do not use MesosScheduler internals, but rely solely on the Framework
 | 
				
			||||||
 | 
					// interface.
 | 
				
			||||||
package operations
 | 
					package operations
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,112 +14,38 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package scheduler
 | 
					package operations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log "github.com/golang/glog"
 | 
						log "github.com/golang/glog"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/runtime"
 | 
					 | 
				
			||||||
	merrors "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/errors"
 | 
						merrors "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/operations"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
 | 
				
			||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/queuer"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/queuer"
 | 
				
			||||||
	types "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/types"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/types"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	apierrors "k8s.io/kubernetes/pkg/api/errors"
 | 
						apierrors "k8s.io/kubernetes/pkg/api/errors"
 | 
				
			||||||
	client "k8s.io/kubernetes/pkg/client/unversioned"
 | 
						client "k8s.io/kubernetes/pkg/client/unversioned"
 | 
				
			||||||
	plugin "k8s.io/kubernetes/plugin/pkg/scheduler"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					// PodReconciler reconciles a pod with the apiserver
 | 
				
			||||||
	pluginRecoveryDelay = 100 * time.Millisecond // delay after scheduler plugin crashes, before we resume scheduling
 | 
					type PodReconciler struct {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	FailedScheduling = "FailedScheduling"
 | 
					 | 
				
			||||||
	Scheduled        = "Scheduled"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type PluginInterface interface {
 | 
					 | 
				
			||||||
	// the apiserver may have a different state for the pod than we do
 | 
					 | 
				
			||||||
	// so reconcile our records, but only for this one pod
 | 
					 | 
				
			||||||
	reconcileTask(*podtask.T)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// execute the Scheduling plugin, should start a go routine and return immediately
 | 
					 | 
				
			||||||
	Run(<-chan struct{})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type PluginConfig struct {
 | 
					 | 
				
			||||||
	*plugin.Config
 | 
					 | 
				
			||||||
	fw      types.Framework
 | 
						fw      types.Framework
 | 
				
			||||||
	client  *client.Client
 | 
						client  *client.Client
 | 
				
			||||||
	qr      *queuer.Queuer
 | 
						qr      *queuer.Queuer
 | 
				
			||||||
	deleter  *operations.Deleter
 | 
						deleter *Deleter
 | 
				
			||||||
	starting chan struct{} // startup latch
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewPlugin(c *PluginConfig) PluginInterface {
 | 
					func NewPodReconciler(fw types.Framework, client *client.Client, qr *queuer.Queuer, deleter *Deleter) *PodReconciler {
 | 
				
			||||||
	return &schedulerPlugin{
 | 
						return &PodReconciler{
 | 
				
			||||||
		config:   c.Config,
 | 
							fw:      fw,
 | 
				
			||||||
		fw:       c.fw,
 | 
							client:  client,
 | 
				
			||||||
		client:   c.client,
 | 
							qr:      qr,
 | 
				
			||||||
		qr:       c.qr,
 | 
							deleter: deleter,
 | 
				
			||||||
		deleter:  c.deleter,
 | 
					 | 
				
			||||||
		starting: c.starting,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type schedulerPlugin struct {
 | 
					 | 
				
			||||||
	config   *plugin.Config
 | 
					 | 
				
			||||||
	fw       types.Framework
 | 
					 | 
				
			||||||
	client   *client.Client
 | 
					 | 
				
			||||||
	qr       *queuer.Queuer
 | 
					 | 
				
			||||||
	deleter  *operations.Deleter
 | 
					 | 
				
			||||||
	starting chan struct{}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *schedulerPlugin) Run(done <-chan struct{}) {
 | 
					 | 
				
			||||||
	defer close(s.starting)
 | 
					 | 
				
			||||||
	go runtime.Until(s.scheduleOne, pluginRecoveryDelay, done)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// hacked from GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/scheduler.go,
 | 
					 | 
				
			||||||
// with the Modeler stuff removed since we don't use it because we have mesos.
 | 
					 | 
				
			||||||
func (s *schedulerPlugin) scheduleOne() {
 | 
					 | 
				
			||||||
	pod := s.config.NextPod()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// pods which are pre-scheduled (i.e. NodeName is set) are deleted by the kubelet
 | 
					 | 
				
			||||||
	// in upstream. Not so in Mesos because the kubelet hasn't see that pod yet. Hence,
 | 
					 | 
				
			||||||
	// the scheduler has to take care of this:
 | 
					 | 
				
			||||||
	if pod.Spec.NodeName != "" && pod.DeletionTimestamp != nil {
 | 
					 | 
				
			||||||
		log.V(3).Infof("deleting pre-scheduled, not yet running pod: %s/%s", pod.Namespace, pod.Name)
 | 
					 | 
				
			||||||
		s.client.Pods(pod.Namespace).Delete(pod.Name, api.NewDeleteOptions(0))
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log.V(3).Infof("Attempting to schedule: %+v", pod)
 | 
					 | 
				
			||||||
	dest, err := s.config.Algorithm.Schedule(pod, s.config.NodeLister) // call kubeScheduler.Schedule
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.V(1).Infof("Failed to schedule: %+v", pod)
 | 
					 | 
				
			||||||
		s.config.Recorder.Eventf(pod, FailedScheduling, "Error scheduling: %v", err)
 | 
					 | 
				
			||||||
		s.config.Error(pod, err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	b := &api.Binding{
 | 
					 | 
				
			||||||
		ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name},
 | 
					 | 
				
			||||||
		Target: api.ObjectReference{
 | 
					 | 
				
			||||||
			Kind: "Node",
 | 
					 | 
				
			||||||
			Name: dest,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := s.config.Binder.Bind(b); err != nil {
 | 
					 | 
				
			||||||
		log.V(1).Infof("Failed to bind pod: %+v", err)
 | 
					 | 
				
			||||||
		s.config.Recorder.Eventf(pod, FailedScheduling, "Binding rejected: %v", err)
 | 
					 | 
				
			||||||
		s.config.Error(pod, err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	s.config.Recorder.Eventf(pod, Scheduled, "Successfully assigned %v to %v", pod.Name, dest)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// this pod may be out of sync with respect to the API server registry:
 | 
					// this pod may be out of sync with respect to the API server registry:
 | 
				
			||||||
//      this pod   |  apiserver registry
 | 
					//      this pod   |  apiserver registry
 | 
				
			||||||
//    -------------|----------------------
 | 
					//    -------------|----------------------
 | 
				
			||||||
@@ -131,7 +57,7 @@ func (s *schedulerPlugin) scheduleOne() {
 | 
				
			|||||||
//      host="..." |  host="..."    ; perhaps no updates to process?
 | 
					//      host="..." |  host="..."    ; perhaps no updates to process?
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// TODO(jdef) this needs an integration test
 | 
					// TODO(jdef) this needs an integration test
 | 
				
			||||||
func (s *schedulerPlugin) reconcileTask(t *podtask.T) {
 | 
					func (s *PodReconciler) Reconcile(t *podtask.T) {
 | 
				
			||||||
	log.V(1).Infof("reconcile pod %v, assigned to slave %q", t.Pod.Name, t.Spec.AssignedSlave)
 | 
						log.V(1).Infof("reconcile pod %v, assigned to slave %q", t.Pod.Name, t.Spec.AssignedSlave)
 | 
				
			||||||
	ctx := api.WithNamespace(api.NewDefaultContext(), t.Pod.Namespace)
 | 
						ctx := api.WithNamespace(api.NewDefaultContext(), t.Pod.Namespace)
 | 
				
			||||||
	pod, err := s.client.Pods(api.NamespaceValue(ctx)).Get(t.Pod.Name)
 | 
						pod, err := s.client.Pods(api.NamespaceValue(ctx)).Get(t.Pod.Name)
 | 
				
			||||||
							
								
								
									
										133
									
								
								contrib/mesos/pkg/scheduler/operations/schedulerloop.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								contrib/mesos/pkg/scheduler/operations/schedulerloop.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 The Kubernetes Authors All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 operations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log "github.com/golang/glog"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/runtime"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/queuer"
 | 
				
			||||||
 | 
						types "k8s.io/kubernetes/contrib/mesos/pkg/scheduler/types"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/client/record"
 | 
				
			||||||
 | 
						client "k8s.io/kubernetes/pkg/client/unversioned"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						recoveryDelay = 100 * time.Millisecond // delay after scheduler plugin crashes, before we resume scheduling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FailedScheduling = "FailedScheduling"
 | 
				
			||||||
 | 
						Scheduled        = "Scheduled"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SchedulerLoopInterface interface {
 | 
				
			||||||
 | 
						ReconcilePodTask(t *podtask.T)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// execute the Scheduling plugin, should start a go routine and return immediately
 | 
				
			||||||
 | 
						Run(<-chan struct{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SchedulerLoopConfig struct {
 | 
				
			||||||
 | 
						Algorithm *SchedulerAlgorithm
 | 
				
			||||||
 | 
						Binder    *Binder
 | 
				
			||||||
 | 
						NextPod   func() *api.Pod
 | 
				
			||||||
 | 
						Error     func(*api.Pod, error)
 | 
				
			||||||
 | 
						Recorder  record.EventRecorder
 | 
				
			||||||
 | 
						Fw        types.Framework
 | 
				
			||||||
 | 
						Client    *client.Client
 | 
				
			||||||
 | 
						Qr        *queuer.Queuer
 | 
				
			||||||
 | 
						Pr        *PodReconciler
 | 
				
			||||||
 | 
						Starting  chan struct{} // startup latch
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewSchedulerLoop(c *SchedulerLoopConfig) SchedulerLoopInterface {
 | 
				
			||||||
 | 
						return &SchedulerLoop{
 | 
				
			||||||
 | 
							algorithm: c.Algorithm,
 | 
				
			||||||
 | 
							binder:    c.Binder,
 | 
				
			||||||
 | 
							nextPod:   c.NextPod,
 | 
				
			||||||
 | 
							error:     c.Error,
 | 
				
			||||||
 | 
							recorder:  c.Recorder,
 | 
				
			||||||
 | 
							fw:        c.Fw,
 | 
				
			||||||
 | 
							client:    c.Client,
 | 
				
			||||||
 | 
							qr:        c.Qr,
 | 
				
			||||||
 | 
							pr:        c.Pr,
 | 
				
			||||||
 | 
							starting:  c.Starting,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SchedulerLoop struct {
 | 
				
			||||||
 | 
						algorithm *SchedulerAlgorithm
 | 
				
			||||||
 | 
						binder    *Binder
 | 
				
			||||||
 | 
						nextPod   func() *api.Pod
 | 
				
			||||||
 | 
						error     func(*api.Pod, error)
 | 
				
			||||||
 | 
						recorder  record.EventRecorder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fw       types.Framework
 | 
				
			||||||
 | 
						client   *client.Client
 | 
				
			||||||
 | 
						qr       *queuer.Queuer
 | 
				
			||||||
 | 
						pr       *PodReconciler
 | 
				
			||||||
 | 
						starting chan struct{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *SchedulerLoop) Run(done <-chan struct{}) {
 | 
				
			||||||
 | 
						defer close(s.starting)
 | 
				
			||||||
 | 
						go runtime.Until(s.scheduleOne, recoveryDelay, done)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hacked from GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/scheduler.go,
 | 
				
			||||||
 | 
					// with the Modeler stuff removed since we don't use it because we have mesos.
 | 
				
			||||||
 | 
					func (s *SchedulerLoop) scheduleOne() {
 | 
				
			||||||
 | 
						pod := s.nextPod()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// pods which are pre-scheduled (i.e. NodeName is set) are deleted by the kubelet
 | 
				
			||||||
 | 
						// in upstream. Not so in Mesos because the kubelet hasn't see that pod yet. Hence,
 | 
				
			||||||
 | 
						// the scheduler has to take care of this:
 | 
				
			||||||
 | 
						if pod.Spec.NodeName != "" && pod.DeletionTimestamp != nil {
 | 
				
			||||||
 | 
							log.V(3).Infof("deleting pre-scheduled, not yet running pod: %s/%s", pod.Namespace, pod.Name)
 | 
				
			||||||
 | 
							s.client.Pods(pod.Namespace).Delete(pod.Name, api.NewDeleteOptions(0))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.V(3).Infof("Attempting to schedule: %+v", pod)
 | 
				
			||||||
 | 
						dest, err := s.algorithm.Schedule(pod)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.V(1).Infof("Failed to schedule: %+v", pod)
 | 
				
			||||||
 | 
							s.recorder.Eventf(pod, FailedScheduling, "Error scheduling: %v", err)
 | 
				
			||||||
 | 
							s.error(pod, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b := &api.Binding{
 | 
				
			||||||
 | 
							ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name},
 | 
				
			||||||
 | 
							Target: api.ObjectReference{
 | 
				
			||||||
 | 
								Kind: "Node",
 | 
				
			||||||
 | 
								Name: dest,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := s.binder.Bind(b); err != nil {
 | 
				
			||||||
 | 
							log.V(1).Infof("Failed to bind pod: %+v", err)
 | 
				
			||||||
 | 
							s.recorder.Eventf(pod, FailedScheduling, "Binding rejected: %v", err)
 | 
				
			||||||
 | 
							s.error(pod, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						s.recorder.Eventf(pod, Scheduled, "Successfully assigned %v to %v", pod.Name, dest)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *SchedulerLoop) ReconcilePodTask(t *podtask.T) {
 | 
				
			||||||
 | 
						s.pr.Reconcile(t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								contrib/mesos/pkg/scheduler/operations/schedulerloop_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contrib/mesos/pkg/scheduler/operations/schedulerloop_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 The Kubernetes Authors All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 operations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test to create the scheduler loop with an empty lopp config
 | 
				
			||||||
 | 
					func TestPlugin_New(t *testing.T) {
 | 
				
			||||||
 | 
						assert := assert.New(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c := SchedulerLoopConfig{}
 | 
				
			||||||
 | 
						p := NewSchedulerLoop(&c)
 | 
				
			||||||
 | 
						assert.NotNil(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -29,7 +29,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type ReconcilerAction func(driver bindings.SchedulerDriver, cancel <-chan struct{}) <-chan error
 | 
					type ReconcilerAction func(driver bindings.SchedulerDriver, cancel <-chan struct{}) <-chan error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Reconciler struct {
 | 
					type TasksReconciler struct {
 | 
				
			||||||
	proc.Doer
 | 
						proc.Doer
 | 
				
			||||||
	Action                             ReconcilerAction
 | 
						Action                             ReconcilerAction
 | 
				
			||||||
	explicit                           chan struct{}   // send an empty struct to trigger explicit reconciliation
 | 
						explicit                           chan struct{}   // send an empty struct to trigger explicit reconciliation
 | 
				
			||||||
@@ -39,9 +39,9 @@ type Reconciler struct {
 | 
				
			|||||||
	explicitReconciliationAbortTimeout time.Duration
 | 
						explicitReconciliationAbortTimeout time.Duration
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewReconciler(doer proc.Doer, action ReconcilerAction,
 | 
					func NewTasksReconciler(doer proc.Doer, action ReconcilerAction,
 | 
				
			||||||
	cooldown, explicitReconciliationAbortTimeout time.Duration, done <-chan struct{}) *Reconciler {
 | 
						cooldown, explicitReconciliationAbortTimeout time.Duration, done <-chan struct{}) *TasksReconciler {
 | 
				
			||||||
	return &Reconciler{
 | 
						return &TasksReconciler{
 | 
				
			||||||
		Doer:     doer,
 | 
							Doer:     doer,
 | 
				
			||||||
		explicit: make(chan struct{}, 1),
 | 
							explicit: make(chan struct{}, 1),
 | 
				
			||||||
		implicit: make(chan struct{}, 1),
 | 
							implicit: make(chan struct{}, 1),
 | 
				
			||||||
@@ -67,14 +67,14 @@ func NewReconciler(doer proc.Doer, action ReconcilerAction,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *Reconciler) RequestExplicit() {
 | 
					func (r *TasksReconciler) RequestExplicit() {
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case r.explicit <- struct{}{}: // noop
 | 
						case r.explicit <- struct{}{}: // noop
 | 
				
			||||||
	default: // request queue full; noop
 | 
						default: // request queue full; noop
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *Reconciler) RequestImplicit() {
 | 
					func (r *TasksReconciler) RequestImplicit() {
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case r.implicit <- struct{}{}: // noop
 | 
						case r.implicit <- struct{}{}: // noop
 | 
				
			||||||
	default: // request queue full; noop
 | 
						default: // request queue full; noop
 | 
				
			||||||
@@ -84,7 +84,7 @@ func (r *Reconciler) RequestImplicit() {
 | 
				
			|||||||
// execute task reconciliation, returns when r.done is closed. intended to run as a goroutine.
 | 
					// execute task reconciliation, returns when r.done is closed. intended to run as a goroutine.
 | 
				
			||||||
// if reconciliation is requested while another is in progress, the in-progress operation will be
 | 
					// if reconciliation is requested while another is in progress, the in-progress operation will be
 | 
				
			||||||
// cancelled before the new reconciliation operation begins.
 | 
					// cancelled before the new reconciliation operation begins.
 | 
				
			||||||
func (r *Reconciler) Run(driver bindings.SchedulerDriver) {
 | 
					func (r *TasksReconciler) Run(driver bindings.SchedulerDriver) {
 | 
				
			||||||
	var cancel, finished chan struct{}
 | 
						var cancel, finished chan struct{}
 | 
				
			||||||
requestLoop:
 | 
					requestLoop:
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
@@ -57,7 +57,6 @@ import (
 | 
				
			|||||||
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
 | 
						kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/labels"
 | 
						"k8s.io/kubernetes/pkg/labels"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/sets"
 | 
						"k8s.io/kubernetes/pkg/util/sets"
 | 
				
			||||||
	plugin "k8s.io/kubernetes/plugin/pkg/scheduler"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// KubernetesScheduler implements:
 | 
					// KubernetesScheduler implements:
 | 
				
			||||||
@@ -100,8 +99,8 @@ type MesosScheduler struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// via deferred init
 | 
						// via deferred init
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	plugin             PluginInterface
 | 
						loop               operations.SchedulerLoopInterface
 | 
				
			||||||
	reconciler         *operations.Reconciler
 | 
						reconciler         *operations.TasksReconciler
 | 
				
			||||||
	reconcileCooldown  time.Duration
 | 
						reconcileCooldown  time.Duration
 | 
				
			||||||
	asRegisteredMaster proc.Doer
 | 
						asRegisteredMaster proc.Doer
 | 
				
			||||||
	terminate          <-chan struct{} // signal chan, closes when we should kill background tasks
 | 
						terminate          <-chan struct{} // signal chan, closes when we should kill background tasks
 | 
				
			||||||
@@ -119,7 +118,7 @@ type Config struct {
 | 
				
			|||||||
	LookupNode        node.LookupFunc
 | 
						LookupNode        node.LookupFunc
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New creates a new KubernetesScheduler
 | 
					// New creates a new MesosScheduler
 | 
				
			||||||
func New(config Config) *MesosScheduler {
 | 
					func New(config Config) *MesosScheduler {
 | 
				
			||||||
	var k *MesosScheduler
 | 
						var k *MesosScheduler
 | 
				
			||||||
	k = &MesosScheduler{
 | 
						k = &MesosScheduler{
 | 
				
			||||||
@@ -178,7 +177,7 @@ func New(config Config) *MesosScheduler {
 | 
				
			|||||||
	return k
 | 
						return k
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (k *MesosScheduler) Init(electedMaster proc.Process, pl PluginInterface, mux *http.ServeMux) error {
 | 
					func (k *MesosScheduler) Init(electedMaster proc.Process, sl operations.SchedulerLoopInterface, mux *http.ServeMux) error {
 | 
				
			||||||
	log.V(1).Infoln("initializing kubernetes mesos scheduler")
 | 
						log.V(1).Infoln("initializing kubernetes mesos scheduler")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	k.asRegisteredMaster = proc.DoerFunc(func(a proc.Action) <-chan error {
 | 
						k.asRegisteredMaster = proc.DoerFunc(func(a proc.Action) <-chan error {
 | 
				
			||||||
@@ -188,7 +187,7 @@ func (k *MesosScheduler) Init(electedMaster proc.Process, pl PluginInterface, mu
 | 
				
			|||||||
		return electedMaster.Do(a)
 | 
							return electedMaster.Do(a)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	k.terminate = electedMaster.Done()
 | 
						k.terminate = electedMaster.Done()
 | 
				
			||||||
	k.plugin = pl
 | 
						k.loop = sl
 | 
				
			||||||
	k.offers.Init(k.terminate)
 | 
						k.offers.Init(k.terminate)
 | 
				
			||||||
	k.InstallDebugHandlers(mux)
 | 
						k.InstallDebugHandlers(mux)
 | 
				
			||||||
	k.nodeRegistrator.Run(k.terminate)
 | 
						k.nodeRegistrator.Run(k.terminate)
 | 
				
			||||||
@@ -296,7 +295,7 @@ func (k *MesosScheduler) onInitialRegistration(driver bindings.SchedulerDriver)
 | 
				
			|||||||
	r1 := k.makeTaskRegistryReconciler()
 | 
						r1 := k.makeTaskRegistryReconciler()
 | 
				
			||||||
	r2 := k.makePodRegistryReconciler()
 | 
						r2 := k.makePodRegistryReconciler()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	k.reconciler = operations.NewReconciler(k.asRegisteredMaster, k.makeCompositeReconciler(r1, r2),
 | 
						k.reconciler = operations.NewTasksReconciler(k.asRegisteredMaster, k.makeCompositeReconciler(r1, r2),
 | 
				
			||||||
		k.reconcileCooldown, k.schedulerConfig.ExplicitReconciliationAbortTimeout.Duration, k.terminate)
 | 
							k.reconcileCooldown, k.schedulerConfig.ExplicitReconciliationAbortTimeout.Duration, k.terminate)
 | 
				
			||||||
	go k.reconciler.Run(driver)
 | 
						go k.reconciler.Run(driver)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -398,7 +397,7 @@ func (k *MesosScheduler) StatusUpdate(driver bindings.SchedulerDriver, taskStatu
 | 
				
			|||||||
	case mesos.TaskState_TASK_FAILED, mesos.TaskState_TASK_ERROR:
 | 
						case mesos.TaskState_TASK_FAILED, mesos.TaskState_TASK_ERROR:
 | 
				
			||||||
		if task, _ := k.taskRegistry.UpdateStatus(taskStatus); task != nil {
 | 
							if task, _ := k.taskRegistry.UpdateStatus(taskStatus); task != nil {
 | 
				
			||||||
			if task.Has(podtask.Launched) && !task.Has(podtask.Bound) {
 | 
								if task.Has(podtask.Launched) && !task.Has(podtask.Bound) {
 | 
				
			||||||
				go k.plugin.reconcileTask(task)
 | 
									go k.loop.ReconcilePodTask(task)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@@ -760,14 +759,14 @@ func (ks *MesosScheduler) recoverTasks() error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create creates a scheduler plugin and all supporting background functions.
 | 
					// Create creates a scheduler plugin and all supporting background functions.
 | 
				
			||||||
func (k *MesosScheduler) NewDefaultPluginConfig(terminate <-chan struct{}, mux *http.ServeMux) *PluginConfig {
 | 
					func (k *MesosScheduler) NewDefaultSchedulerLoopConfig(terminate <-chan struct{}, mux *http.ServeMux) *operations.SchedulerLoopConfig {
 | 
				
			||||||
	// use ListWatch watching pods using the client by default
 | 
						// use ListWatch watching pods using the client by default
 | 
				
			||||||
	lw := cache.NewListWatchFromClient(k.client, "pods", api.NamespaceAll, fields.Everything())
 | 
						lw := cache.NewListWatchFromClient(k.client, "pods", api.NamespaceAll, fields.Everything())
 | 
				
			||||||
	return k.NewPluginConfig(terminate, mux, lw)
 | 
						return k.NewSchedulerLoopConfig(terminate, mux, lw)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (k *MesosScheduler) NewPluginConfig(terminate <-chan struct{}, mux *http.ServeMux,
 | 
					func (k *MesosScheduler) NewSchedulerLoopConfig(terminate <-chan struct{}, mux *http.ServeMux,
 | 
				
			||||||
	podsWatcher *cache.ListWatch) *PluginConfig {
 | 
						podsWatcher *cache.ListWatch) *operations.SchedulerLoopConfig {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Watch and queue pods that need scheduling.
 | 
						// Watch and queue pods that need scheduling.
 | 
				
			||||||
	updates := make(chan queue.Entry, k.schedulerConfig.UpdatesBacklog)
 | 
						updates := make(chan queue.Entry, k.schedulerConfig.UpdatesBacklog)
 | 
				
			||||||
@@ -780,6 +779,7 @@ func (k *MesosScheduler) NewPluginConfig(terminate <-chan struct{}, mux *http.Se
 | 
				
			|||||||
	scheduler := &mesosFramework{mesosScheduler: k}
 | 
						scheduler := &mesosFramework{mesosScheduler: k}
 | 
				
			||||||
	q := queuer.New(podUpdates)
 | 
						q := queuer.New(podUpdates)
 | 
				
			||||||
	podDeleter := operations.NewDeleter(scheduler, q)
 | 
						podDeleter := operations.NewDeleter(scheduler, q)
 | 
				
			||||||
 | 
						podReconciler := operations.NewPodReconciler(scheduler, k.client, q, podDeleter)
 | 
				
			||||||
	bo := backoff.New(k.schedulerConfig.InitialPodBackoff.Duration, k.schedulerConfig.MaxPodBackoff.Duration)
 | 
						bo := backoff.New(k.schedulerConfig.InitialPodBackoff.Duration, k.schedulerConfig.MaxPodBackoff.Duration)
 | 
				
			||||||
	eh := operations.NewErrorHandler(scheduler, bo, q)
 | 
						eh := operations.NewErrorHandler(scheduler, bo, q)
 | 
				
			||||||
	startLatch := make(chan struct{})
 | 
						startLatch := make(chan struct{})
 | 
				
			||||||
@@ -793,22 +793,16 @@ func (k *MesosScheduler) NewPluginConfig(terminate <-chan struct{}, mux *http.Se
 | 
				
			|||||||
		q.InstallDebugHandlers(mux)
 | 
							q.InstallDebugHandlers(mux)
 | 
				
			||||||
		podtask.InstallDebugHandlers(k.taskRegistry, mux)
 | 
							podtask.InstallDebugHandlers(k.taskRegistry, mux)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	return &PluginConfig{
 | 
						return &operations.SchedulerLoopConfig{
 | 
				
			||||||
		Config: &plugin.Config{
 | 
							Algorithm: operations.NewSchedulerAlgorithm(scheduler, podUpdates),
 | 
				
			||||||
			NodeLister: nil,
 | 
					 | 
				
			||||||
			Algorithm: &mesosSchedulerAlgorithm{
 | 
					 | 
				
			||||||
				fw:         scheduler,
 | 
					 | 
				
			||||||
				podUpdates: podUpdates,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		Binder:    operations.NewBinder(scheduler),
 | 
							Binder:    operations.NewBinder(scheduler),
 | 
				
			||||||
		NextPod:   q.Yield,
 | 
							NextPod:   q.Yield,
 | 
				
			||||||
		Error:     eh.Error,
 | 
							Error:     eh.Error,
 | 
				
			||||||
		Recorder:  eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}),
 | 
							Recorder:  eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}),
 | 
				
			||||||
		},
 | 
							Fw:        scheduler,
 | 
				
			||||||
		fw:       scheduler,
 | 
							Client:    k.client,
 | 
				
			||||||
		client:   k.client,
 | 
							Qr:        q,
 | 
				
			||||||
		qr:       q,
 | 
							Pr:        podReconciler,
 | 
				
			||||||
		deleter:  podDeleter,
 | 
							Starting:  startLatch,
 | 
				
			||||||
		starting: startLatch,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/slave"
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/slave"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/client/cache"
 | 
						"k8s.io/kubernetes/pkg/client/cache"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/mock"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//get number of non-expired offers from  offer registry
 | 
					//get number of non-expired offers from  offer registry
 | 
				
			||||||
@@ -283,7 +284,7 @@ func TestDisconnect(t *testing.T) {
 | 
				
			|||||||
//test we can handle different status updates, TODO check state transitions
 | 
					//test we can handle different status updates, TODO check state transitions
 | 
				
			||||||
func TestStatus_Update(t *testing.T) {
 | 
					func TestStatus_Update(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mockdriver := MockSchedulerDriver{}
 | 
						mockdriver := mock.MockSchedulerDriver{}
 | 
				
			||||||
	// setup expectations
 | 
						// setup expectations
 | 
				
			||||||
	mockdriver.On("KillTask", util.NewTaskID("test-task-001")).Return(mesos.Status_DRIVER_RUNNING, nil)
 | 
						mockdriver.On("KillTask", util.NewTaskID("test-task-001")).Return(mesos.Status_DRIVER_RUNNING, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,6 +73,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/master/ports"
 | 
						"k8s.io/kubernetes/pkg/master/ports"
 | 
				
			||||||
	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
 | 
						etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/tools"
 | 
						"k8s.io/kubernetes/pkg/tools"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/operations"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -758,13 +759,13 @@ func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kpl := scheduler.NewPlugin(mesosPodScheduler.NewDefaultPluginConfig(schedulerProcess.Terminal(), s.mux))
 | 
						loop := operations.NewSchedulerLoop(mesosPodScheduler.NewDefaultSchedulerLoopConfig(schedulerProcess.Terminal(), s.mux))
 | 
				
			||||||
	runtime.On(mesosPodScheduler.Registration(), func() { kpl.Run(schedulerProcess.Terminal()) })
 | 
						runtime.On(mesosPodScheduler.Registration(), func() { loop.Run(schedulerProcess.Terminal()) })
 | 
				
			||||||
	runtime.On(mesosPodScheduler.Registration(), s.newServiceWriter(schedulerProcess.Terminal()))
 | 
						runtime.On(mesosPodScheduler.Registration(), s.newServiceWriter(schedulerProcess.Terminal()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	driverFactory := ha.DriverFactory(func() (drv bindings.SchedulerDriver, err error) {
 | 
						driverFactory := ha.DriverFactory(func() (drv bindings.SchedulerDriver, err error) {
 | 
				
			||||||
		log.V(1).Infoln("performing deferred initialization")
 | 
							log.V(1).Infoln("performing deferred initialization")
 | 
				
			||||||
		if err = mesosPodScheduler.Init(schedulerProcess.Master(), kpl, s.mux); err != nil {
 | 
							if err = mesosPodScheduler.Init(schedulerProcess.Master(), loop, s.mux); err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("failed to initialize pod scheduler: %v", err)
 | 
								return nil, fmt.Errorf("failed to initialize pod scheduler: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log.V(1).Infoln("deferred init complete")
 | 
							log.V(1).Infoln("deferred init complete")
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user