Beispiel #1
0
func (TestSuite) TestFindJobToStop(c *C) {
	s := &Scheduler{
		isLeader: typeconv.BoolPtr(true),
		jobs:     make(Jobs),
		logger:   log15.New(),
	}

	// populate s.jobs with jobs in various states, oldest first
	formation := &Formation{}
	typ := "web"
	start := time.Now()
	startedAt := func(i int) time.Time {
		return start.Add(time.Duration(int64(i)) * time.Second)
	}
	for i, state := range []JobState{
		JobStatePending,
		JobStateStarting,
		JobStateRunning,
		JobStatePending,
		JobStateStarting,
		JobStateRunning,
		JobStateStopping,
		JobStateStopped,
		JobStatePending,
		JobStateStarting,
		JobStateRunning,
	} {
		id := fmt.Sprintf("job%d", i)
		s.jobs[id] = &Job{
			ID:        id,
			Formation: formation,
			Type:      typ,
			StartedAt: startedAt(i),
			State:     state,
		}
	}

	nextJob := func() *Job {
		job, err := s.findJobToStop(formation, typ)
		c.Assert(err, IsNil)
		delete(s.jobs, job.ID)
		return job
	}

	// expect the three pending jobs first
	c.Assert(nextJob().State, Equals, JobStatePending)
	c.Assert(nextJob().State, Equals, JobStatePending)
	c.Assert(nextJob().State, Equals, JobStatePending)

	// then the starting jobs, newest first
	c.Assert(nextJob().ID, Equals, "job9")
	c.Assert(nextJob().ID, Equals, "job4")
	c.Assert(nextJob().ID, Equals, "job1")

	// then the running jobs, newest first
	c.Assert(nextJob().ID, Equals, "job10")
	c.Assert(nextJob().ID, Equals, "job5")
	c.Assert(nextJob().ID, Equals, "job2")
}
Beispiel #2
0
func (TestSuite) TestJobPlacementTags(c *C) {
	// create a scheduler with tagged hosts
	s := &Scheduler{
		isLeader: typeconv.BoolPtr(true),
		jobs:     make(Jobs),
		hosts: map[string]*Host{
			"host1": {ID: "host1", Tags: map[string]string{"disk": "mag", "cpu": "fast"}},
			"host2": {ID: "host2", Tags: map[string]string{"disk": "ssd", "cpu": "slow"}},
			"host3": {ID: "host3", Tags: map[string]string{"disk": "ssd", "cpu": "fast"}},
		},
		logger: log15.New(),
	}

	// use a formation with tagged process types
	formation := NewFormation(&ct.ExpandedFormation{
		App: &ct.App{ID: "app"},
		Release: &ct.Release{ID: "release", Processes: map[string]ct.ProcessType{
			"web":    {},
			"db":     {},
			"worker": {},
			"clock":  {},
		}},
		ImageArtifact: &ct.Artifact{},
		Tags: map[string]map[string]string{
			"web":    nil,
			"db":     {"disk": "ssd"},
			"worker": {"cpu": "fast"},
			"clock":  {"disk": "ssd", "cpu": "slow"},
		},
	})

	// continually place jobs, and check they get placed in a round-robin
	// fashion on the hosts matching the type's tags
	type test struct {
		typ  string
		host string
	}
	for i, t := range []*test{
		// web go on all hosts
		{typ: "web", host: "host1"},
		{typ: "web", host: "host2"},
		{typ: "web", host: "host3"},
		{typ: "web", host: "host1"},
		{typ: "web", host: "host2"},
		{typ: "web", host: "host3"},
		// db go on hosts 2 and 3

		{typ: "db", host: "host2"},
		{typ: "db", host: "host3"},
		{typ: "db", host: "host2"},
		{typ: "db", host: "host3"},
		// worker go on hosts 1 and 3

		{typ: "worker", host: "host1"},
		{typ: "worker", host: "host3"},
		{typ: "worker", host: "host1"},
		{typ: "worker", host: "host3"},

		// clock go on host 2
		{typ: "clock", host: "host2"},
		{typ: "clock", host: "host2"},
		{typ: "clock", host: "host2"},
	} {
		job := s.jobs.Add(&Job{ID: fmt.Sprintf("job%d", i), Formation: formation, Type: t.typ, state: JobStatePending})
		req := &PlacementRequest{Job: job, Err: make(chan error, 1)}
		s.HandlePlacementRequest(req)
		c.Assert(<-req.Err, IsNil, Commentf("placing job %d", i))
		c.Assert(req.Host.ID, Equals, t.host, Commentf("placing job %d", i))
	}
}