func updateStatusForTask(status *mesos.TaskStatus) { id := status.TaskId.GetValue() log.Debugf("TaskId [%s] status [%s]", id, status.State) task, _ := database.ReadTask(id) task.Status = status.State.String() database.PutTask(&task) }
// GetTaskInfo returns information about the given task. func GetTaskInfo(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["taskId"] log.Debugf("Fetching task for id: %s", id) task, _ := database.ReadTask(id) if strings.Contains(r.Header.Get("Accept"), "text/html") { renderHTML(w, r, task, id) } else { if task == (types.EremeticTask{}) { writeJSON(http.StatusNotFound, nil, w) return } writeJSON(http.StatusOK, task, w) } }
// ResourceOffers handles the Resource Offers func (s *eremeticScheduler) ResourceOffers(driver sched.SchedulerDriver, offers []*mesos.Offer) { log.Tracef("Received %d resource offers", len(offers)) for _, offer := range offers { select { case <-s.shutdown: log.Infof("Shutting down: declining offer on [%s]", offer.Hostname) driver.DeclineOffer(offer.Id, defaultFilter) continue case tid := <-s.tasks: log.Debugf("Preparing to launch task %s with offer %s", tid, offer.Id.GetValue()) t, _ := database.ReadTask(tid) task := s.newTask(offer, &t) database.PutTask(&t) driver.LaunchTasks([]*mesos.OfferID{offer.Id}, []*mesos.TaskInfo{task}, defaultFilter) continue default: } log.Trace("No tasks to launch. Declining offer.") driver.DeclineOffer(offer.Id, defaultFilter) } }
func TestScheduler(t *testing.T) { dir, _ := os.Getwd() database.NewDB(fmt.Sprintf("%s/../db/test.db", dir)) database.Clean() defer database.Close() Convey("eremeticScheduler", t, func() { s := eremeticScheduler{} id := "eremetic-task.9999" database.PutTask(&types.EremeticTask{ID: id}) Convey("newTask", func() { task := types.EremeticTask{ ID: "eremetic-task.1234", } offer := mesos.Offer{ FrameworkId: &mesos.FrameworkID{ Value: proto.String("framework-id"), }, SlaveId: &mesos.SlaveID{ Value: proto.String("slave-id"), }, Hostname: proto.String("hostname"), } newTask := s.newTask(&offer, &task) So(newTask.GetTaskId().GetValue(), ShouldEqual, task.ID) }) Convey("createEremeticScheduler", func() { s := createEremeticScheduler() So(s.tasksCreated, ShouldEqual, 0) }) Convey("API", func() { Convey("Registered", func() { fID := mesos.FrameworkID{Value: proto.String("1234")} mInfo := mesos.MasterInfo{} s.Registered(nil, &fID, &mInfo) }) Convey("Reregistered", func() { s.Reregistered(nil, &mesos.MasterInfo{}) }) Convey("Disconnected", func() { s.Disconnected(nil) }) Convey("ResourceOffers", func() { driver := NewMockScheduler() var offers []*mesos.Offer Convey("No offers", func() { s.ResourceOffers(driver, offers) So(driver.AssertNotCalled(t, "DeclineOffer"), ShouldBeTrue) So(driver.AssertNotCalled(t, "LaunchTasks"), ShouldBeTrue) }) Convey("No tasks", func() { offers = append(offers, &mesos.Offer{Id: &mesos.OfferID{Value: proto.String("1234")}}) driver.On("DeclineOffer").Return("declined").Once() s.ResourceOffers(driver, offers) So(driver.AssertCalled(t, "DeclineOffer"), ShouldBeTrue) So(driver.AssertNotCalled(t, "LaunchTasks"), ShouldBeTrue) }) }) Convey("StatusUpdate", func() { s.StatusUpdate(nil, &mesos.TaskStatus{ TaskId: &mesos.TaskID{ Value: proto.String(id), }, State: mesos.TaskState_TASK_FAILED.Enum(), }) task, _ := database.ReadTask(id) So(task.Status, ShouldEqual, "TASK_FAILED") }) Convey("FrameworkMessage", func() { driver := NewMockScheduler() message := `{"message": "this is a message"}` Convey("From Eremetic", func() { source := "eremetic-executor" executor := mesos.ExecutorID{ Value: proto.String(source), } s.FrameworkMessage(driver, &executor, &mesos.SlaveID{}, message) }) Convey("From an unknown source", func() { source := "other-source" executor := mesos.ExecutorID{ Value: proto.String(source), } s.FrameworkMessage(driver, &executor, &mesos.SlaveID{}, message) }) Convey("A bad json", func() { source := "eremetic-executor" executor := mesos.ExecutorID{ Value: proto.String(source), } s.FrameworkMessage(driver, &executor, &mesos.SlaveID{}, "not a json") }) }) Convey("OfferRescinded", func() { s.OfferRescinded(nil, &mesos.OfferID{}) }) Convey("SlaveLost", func() { s.SlaveLost(nil, &mesos.SlaveID{}) }) Convey("ExecutorLost", func() { s.ExecutorLost(nil, &mesos.ExecutorID{}, &mesos.SlaveID{}, 2) }) Convey("Error", func() { s.Error(nil, "Error") }) }) }) Convey("scheduleTask", t, func() { Convey("Given a valid Request", func() { scheduler := &eremeticScheduler{ tasks: make(chan string, 100), } request := types.Request{ TaskCPUs: 0.5, TaskMem: 22.0, DockerImage: "busybox", Command: "echo hello", } Convey("It should put a task id on the channel", func() { taskID, err := scheduleTask(scheduler, request) So(err, ShouldBeNil) select { case c := <-scheduler.tasks: So(c, ShouldEqual, taskID) task, _ := database.ReadTask(taskID) So(task.TaskCPUs, ShouldEqual, request.TaskCPUs) So(task.TaskMem, ShouldEqual, request.TaskMem) So(task.Command.GetValue(), ShouldEqual, request.Command) So(*task.Container.Docker.Image, ShouldEqual, request.DockerImage) So(task.ID, ShouldStartWith, "eremetic-task.") } }) }) }) }