func (driver *MesosSchedulerDriver) AcceptOffers(offerIDs []*mesos.OfferID, operations []*mesos.Offer_Operation, filters *mesos.Filters) (mesos.Status, error) { driver.eventLock.Lock() defer driver.eventLock.Unlock() if stat := driver.status; stat != mesos.Status_DRIVER_RUNNING { return stat, fmt.Errorf("Unable to AcceptOffers, expected driver status %s, but got %s", mesos.Status_DRIVER_RUNNING, stat) } // Launch tasks if !driver.connected { log.Infoln("Ignoring AcceptOffers message, disconnected from master.") return driver.status, fmt.Errorf("Not connected to master.") } okOperations := make([]*mesos.Offer_Operation, 0, len(operations)) for _, offerID := range offerIDs { for _, operation := range operations { // Keep only the slave PIDs where we run tasks so we can send // framework messages directly. if driver.cache.containsOffer(offerID) { // Validate switch *operation.Type { case mesos.Offer_Operation_LAUNCH: tasks := []*mesos.TaskInfo{} // Set TaskInfo.executor.framework_id, if it's missing. for _, task := range operation.Launch.TaskInfos { newTask := *task if newTask.Executor != nil && newTask.Executor.FrameworkId == nil { newTask.Executor.FrameworkId = driver.frameworkInfo.Id } tasks = append(tasks, &newTask) } for _, task := range tasks { if driver.cache.getOffer(offerID).offer.SlaveId.Equal(task.SlaveId) { // cache the tasked slave, for future communication pid := driver.cache.getOffer(offerID).slavePid driver.cache.putSlavePid(task.SlaveId, pid) } else { log.Warningf("Attempting to launch task %s with the wrong slaveId offer %s\n", task.TaskId.GetValue(), task.SlaveId.GetValue()) } } operation.Launch.TaskInfos = tasks okOperations = append(okOperations, operation) case mesos.Offer_Operation_RESERVE: filtered := util.FilterResources(operation.Reserve.Resources, func(res *mesos.Resource) bool { return res.Reservation != nil }) operation.Reserve.Resources = filtered okOperations = append(okOperations, operation) case mesos.Offer_Operation_UNRESERVE: filtered := util.FilterResources(operation.Unreserve.Resources, func(res *mesos.Resource) bool { return res.Reservation != nil }) operation.Unreserve.Resources = filtered okOperations = append(okOperations, operation) case mesos.Offer_Operation_CREATE: filtered := util.FilterResources(operation.Create.Volumes, func(res *mesos.Resource) bool { return res.Reservation != nil && res.Disk != nil && res.GetName() == "disk" }) operation.Create.Volumes = filtered okOperations = append(okOperations, operation) case mesos.Offer_Operation_DESTROY: filtered := util.FilterResources(operation.Destroy.Volumes, func(res *mesos.Resource) bool { return res.Reservation != nil && res.Disk != nil && res.GetName() == "disk" }) operation.Destroy.Volumes = filtered okOperations = append(okOperations, operation) } } else { log.Warningf("Attempting to accept offers with unknown offer %s\n", offerID.GetValue()) } } driver.cache.removeOffer(offerID) // if offer } // Accept Offers accept := &mesos.Call_Accept{ OfferIds: offerIDs, Operations: okOperations, Filters: filters, } callType := mesos.Call_ACCEPT message := &mesos.Call{ FrameworkId: driver.frameworkInfo.Id, Type: &callType, Accept: accept, } if err := driver.send(driver.masterPid, message); err != nil { for _, operation := range operations { if *operation.Type == mesos.Offer_Operation_LAUNCH { for _, task := range operation.Launch.TaskInfos { driver.pushLostTask(task, "Unable to launch tasks: "+err.Error()) } } } log.Errorf("Failed to send LaunchTask message: %v\n", err) return driver.status, err } return driver.status, nil }
func (sched *ExampleScheduler) ResourceOffers(driver sched.SchedulerDriver, offers []*mesos.Offer) { if sched.tasksLaunched >= sched.totalTasks { log.Info("decline all of the offers since all of our tasks are already launched") ids := make([]*mesos.OfferID, len(offers)) for i, offer := range offers { ids[i] = offer.Id } driver.LaunchTasks(ids, []*mesos.TaskInfo{}, &mesos.Filters{RefuseSeconds: proto.Float64(120)}) return } for _, offer := range offers { cpuResources := util.FilterResources(offer.Resources, func(res *mesos.Resource) bool { return res.GetName() == "cpus" }) cpus := 0.0 for _, res := range cpuResources { cpus += res.GetScalar().GetValue() } memResources := util.FilterResources(offer.Resources, func(res *mesos.Resource) bool { return res.GetName() == "mem" }) mems := 0.0 for _, res := range memResources { mems += res.GetScalar().GetValue() } log.Infoln("Received Offer <", offer.Id.GetValue(), "> with cpus=", cpus, " mem=", mems) remainingCpus := cpus remainingMems := mems var tasks []*mesos.TaskInfo for sched.tasksLaunched < sched.totalTasks && CPUS_PER_TASK <= remainingCpus && MEM_PER_TASK <= remainingMems { sched.tasksLaunched++ taskId := &mesos.TaskID{ Value: proto.String(strconv.Itoa(sched.tasksLaunched)), } task := &mesos.TaskInfo{ Name: proto.String("go-task-" + taskId.GetValue()), TaskId: taskId, SlaveId: offer.SlaveId, Executor: sched.executor, Resources: []*mesos.Resource{ util.NewScalarResource("cpus", CPUS_PER_TASK), util.NewScalarResource("mem", MEM_PER_TASK), }, } log.Infof("Prepared task: %s with offer %s for launch\n", task.GetName(), offer.Id.GetValue()) tasks = append(tasks, task) remainingCpus -= CPUS_PER_TASK remainingMems -= MEM_PER_TASK } log.Infoln("Launching ", len(tasks), "tasks for offer", offer.Id.GetValue()) driver.LaunchTasks([]*mesos.OfferID{offer.Id}, tasks, &mesos.Filters{RefuseSeconds: proto.Float64(5)}) } }