func newLifecycleTest(t *testing.T) lifecycleTest { assert := &EventAssertions{*assert.New(t)} // create a fake pod watch. We use that below to submit new pods to the scheduler podsListWatch := NewMockPodsListWatch(api.PodList{}) // create fake apiserver apiServer := NewTestServer(t, api.NamespaceDefault, podsListWatch) // create ExecutorInfo with some data for static pods if set ei := mesosutil.NewExecutorInfo( mesosutil.NewExecutorID("executor-id"), mesosutil.NewCommandInfo("executor-cmd"), ) ei.Data = []byte{0, 1, 2} // create framework client := client.NewOrDie(&client.Config{ Host: apiServer.server.URL, GroupVersion: testapi.Default.GroupVersion(), }) c := *schedcfg.CreateDefaultConfig() fw := framework.New(framework.Config{ Executor: ei, Client: client, SchedulerConfig: c, LookupNode: apiServer.LookupNode, }) // TODO(sttts): re-enable the following tests // assert.NotNil(framework.client, "client is nil") // assert.NotNil(framework.executor, "executor is nil") // assert.NotNil(framework.offers, "offer registry is nil") // create pod scheduler strategy := podschedulers.NewAllocationStrategy( podtask.NewDefaultPredicate( mresource.DefaultDefaultContainerCPULimit, mresource.DefaultDefaultContainerMemLimit, ), podtask.NewDefaultProcurement( mresource.DefaultDefaultContainerCPULimit, mresource.DefaultDefaultContainerMemLimit, ), ) fcfs := podschedulers.NewFCFSPodScheduler(strategy, apiServer.LookupNode) // create scheduler process schedulerProc := ha.New(fw) // create scheduler eventObs := NewEventObserver() scheduler := components.New(&c, fw, fcfs, client, eventObs, schedulerProc.Terminal(), http.DefaultServeMux, &podsListWatch.ListWatch) assert.NotNil(scheduler) // create mock mesos scheduler driver driver := &framework.JoinableDriver{} return lifecycleTest{ apiServer: apiServer, driver: driver, eventObs: eventObs, podsListWatch: podsListWatch, framework: fw, schedulerProc: schedulerProc, sched: scheduler, t: t, } }
func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config) (*ha.SchedulerProcess, ha.DriverFactory, tools.EtcdClient, *uid.UID) { s.frameworkName = strings.TrimSpace(s.frameworkName) if s.frameworkName == "" { log.Fatalf("framework-name must be a non-empty string") } s.frameworkWebURI = strings.TrimSpace(s.frameworkWebURI) metrics.Register() runtime.Register() s.mux.Handle("/metrics", prometheus.Handler()) healthz.InstallHandler(s.mux) if (s.etcdConfigFile != "" && len(s.etcdServerList) != 0) || (s.etcdConfigFile == "" && len(s.etcdServerList) == 0) { log.Fatalf("specify either --etcd-servers or --etcd-config") } if len(s.apiServerList) < 1 { log.Fatal("No api servers specified.") } client, err := s.createAPIServerClient() if err != nil { log.Fatalf("Unable to make apiserver client: %v", err) } s.client = client if s.reconcileCooldown < defaultReconcileCooldown { s.reconcileCooldown = defaultReconcileCooldown log.Warningf("user-specified reconcile cooldown too small, defaulting to %v", s.reconcileCooldown) } executor, eid, err := s.prepareExecutorInfo(hks) if err != nil { log.Fatalf("misconfigured executor: %v", err) } // TODO(jdef): remove the dependency on etcd as soon as // (1) the generic config store is available for the FrameworkId storage // (2) the generic master election is provided by the apiserver // Compare docs/proposals/high-availability.md etcdClient, err := newEtcd(s.etcdConfigFile, s.etcdServerList) if err != nil { log.Fatalf("misconfigured etcd: %v", err) } as := podschedulers.NewAllocationStrategy( podtask.NewDefaultPredicate( s.defaultContainerCPULimit, s.defaultContainerMemLimit, ), podtask.NewDefaultProcurement( s.defaultContainerCPULimit, s.defaultContainerMemLimit, ), ) // downgrade allocation strategy if user disables "account-for-pod-resources" if !s.accountForPodResources { as = podschedulers.NewAllocationStrategy( podtask.DefaultMinimalPredicate, podtask.DefaultMinimalProcurement) } // mirror all nodes into the nodeStore nodesClient, err := s.createAPIServerClient() if err != nil { log.Fatalf("Cannot create client to watch nodes: %v", err) } nodeStore := cache.NewStore(cache.MetaNamespaceKeyFunc) nodeLW := cache.NewListWatchFromClient(nodesClient, "nodes", api.NamespaceAll, fields.Everything()) cache.NewReflector(nodeLW, &api.Node{}, nodeStore, s.nodeRelistPeriod).Run() lookupNode := func(hostName string) *api.Node { n, _, _ := nodeStore.GetByKey(hostName) // ignore error and return nil then if n == nil { return nil } return n.(*api.Node) } fcfs := podschedulers.NewFCFSPodScheduler(as, lookupNode) framework := framework.New(framework.Config{ SchedulerConfig: *sc, Executor: executor, Client: client, FailoverTimeout: s.failoverTimeout, ReconcileInterval: s.reconcileInterval, ReconcileCooldown: s.reconcileCooldown, LookupNode: lookupNode, StoreFrameworkId: func(id string) { // TODO(jdef): port FrameworkId store to generic Kubernetes config store as soon as available _, err := etcdClient.Set(meta.FrameworkIDKey, id, uint64(s.failoverTimeout)) if err != nil { log.Errorf("failed to renew frameworkId TTL: %v", err) } }, }) masterUri := s.mesosMaster info, cred, err := s.buildFrameworkInfo() if err != nil { log.Fatalf("Misconfigured mesos framework: %v", err) } schedulerProcess := ha.New(framework) dconfig := &bindings.DriverConfig{ Scheduler: schedulerProcess, Framework: info, Master: masterUri, Credential: cred, BindingAddress: s.address, BindingPort: uint16(s.driverPort), HostnameOverride: s.hostnameOverride, WithAuthContext: func(ctx context.Context) context.Context { ctx = auth.WithLoginProvider(ctx, s.mesosAuthProvider) ctx = sasl.WithBindingAddress(ctx, s.address) return ctx }, } // create event recorder sending events to the "" namespace of the apiserver broadcaster := record.NewBroadcaster() recorder := broadcaster.NewRecorder(api.EventSource{Component: "scheduler"}) broadcaster.StartRecordingToSink(client.Events("")) // create scheduler core with all components arranged around it lw := cache.NewListWatchFromClient(client, "pods", api.NamespaceAll, fields.Everything()) sched := components.New(sc, framework, fcfs, client, recorder, schedulerProcess.Terminal(), s.mux, lw) runtime.On(framework.Registration(), func() { sched.Run(schedulerProcess.Terminal()) }) runtime.On(framework.Registration(), s.newServiceWriter(schedulerProcess.Terminal())) driverFactory := ha.DriverFactory(func() (drv bindings.SchedulerDriver, err error) { log.V(1).Infoln("performing deferred initialization") if err = framework.Init(sched, schedulerProcess.Master(), s.mux); err != nil { return nil, fmt.Errorf("failed to initialize pod scheduler: %v", err) } log.V(1).Infoln("deferred init complete") // defer obtaining framework ID to prevent multiple schedulers // from overwriting each other's framework IDs dconfig.Framework.Id, err = s.fetchFrameworkID(etcdClient) if err != nil { return nil, fmt.Errorf("failed to fetch framework ID from etcd: %v", err) } log.V(1).Infoln("constructing mesos scheduler driver") drv, err = bindings.NewMesosSchedulerDriver(*dconfig) if err != nil { return nil, fmt.Errorf("failed to construct scheduler driver: %v", err) } log.V(1).Infoln("constructed mesos scheduler driver:", drv) s.setDriver(drv) return drv, nil }) return schedulerProcess, driverFactory, etcdClient, eid }