// assumes that: caller has acquired scheduler lock and that the task is still pending // // bind does not actually do the binding itself, but launches the pod as a Mesos task. The // kubernetes executor on the slave will finally do the binding. This is different from the // upstream scheduler in the sense that the upstream scheduler does the binding and the // kubelet will notice that and launches the pod. func (b *binder) bind(ctx api.Context, binding *api.Binding, task *podtask.T) (err error) { // sanity check: ensure that the task hasAcceptedOffer(), it's possible that between // Schedule() and now that the offer for this task was rescinded or invalidated. // ((we should never see this here)) if !task.HasAcceptedOffer() { return fmt.Errorf("task has not accepted a valid offer %v", task.ID) } // By this time, there is a chance that the slave is disconnected. offerId := task.GetOfferId() if offer, ok := b.api.offers().Get(offerId); !ok || offer.HasExpired() { // already rescinded or timed out or otherwise invalidated return b.rollback(task, fmt.Errorf("failed prior to launchTask due to expired offer for task %v", task.ID)) } if err = b.prepareTaskForLaunch(ctx, binding.Target.Name, task, offerId); err == nil { log.V(2).Infof("launching task: %q on target %q slave %q for pod \"%v/%v\", cpu %.2f, mem %.2f MB", task.ID, binding.Target.Name, task.Spec.SlaveID, task.Pod.Namespace, task.Pod.Name, task.Spec.CPU, task.Spec.Memory) if err = b.api.launchTask(task); err == nil { b.api.offers().Invalidate(offerId) task.Set(podtask.Launched) if err = b.api.tasks().Update(task); err != nil { // this should only happen if the task has been removed or has changed status, // which SHOULD NOT HAPPEN as long as we're synchronizing correctly log.Errorf("failed to update task w/ Launched status: %v", err) } return } } return b.rollback(task, fmt.Errorf("Failed to launch task %v: %v", task.ID, err)) }