// asyncPlanWait is used to apply and respond to a plan async func (s *Server) asyncPlanWait(waitCh chan struct{}, future raft.ApplyFuture, result *structs.PlanResult, pending *pendingPlan) { defer metrics.MeasureSince([]string{"nomad", "plan", "apply"}, time.Now()) defer close(waitCh) // Wait for the plan to apply if err := future.Error(); err != nil { s.logger.Printf("[ERR] nomad: failed to apply plan: %v", err) pending.respond(nil, err) return } // Respond to the plan result.AllocIndex = future.Index() pending.respond(result, nil) }
// SubmitPlan is used to handle plan submission func (h *Harness) SubmitPlan(plan *structs.Plan) (*structs.PlanResult, State, error) { // Ensure sequential plan application h.planLock.Lock() defer h.planLock.Unlock() // Store the plan h.Plans = append(h.Plans, plan) // Check for custom planner if h.Planner != nil { return h.Planner.SubmitPlan(plan) } // Get the index index := h.NextIndex() // Prepare the result result := new(structs.PlanResult) result.NodeUpdate = plan.NodeUpdate result.NodeAllocation = plan.NodeAllocation result.AllocIndex = index // Flatten evicts and allocs var allocs []*structs.Allocation for _, updateList := range plan.NodeUpdate { allocs = append(allocs, updateList...) } for _, allocList := range plan.NodeAllocation { allocs = append(allocs, allocList...) } allocs = append(allocs, plan.FailedAllocs...) // Attach the plan to all the allocations. It is pulled out in the // payload to avoid the redundancy of encoding, but should be denormalized // prior to being inserted into MemDB. if j := plan.Job; j != nil { for _, alloc := range allocs { if alloc.Job == nil { alloc.Job = j } } } // Apply the full plan err := h.State.UpsertAllocs(index, allocs) return result, nil, err }
// asyncPlanWait is used to apply and respond to a plan async func (s *Server) asyncPlanWait(waitCh chan struct{}, future raft.ApplyFuture, result *structs.PlanResult, pending *pendingPlan) { defer metrics.MeasureSince([]string{"nomad", "plan", "apply"}, time.Now()) defer close(waitCh) // Wait for the plan to apply if err := future.Error(); err != nil { s.logger.Printf("[ERR] nomad: failed to apply plan: %v", err) pending.respond(nil, err) return } // Respond to the plan result.AllocIndex = future.Index() // If this is a partial plan application, we need to ensure the scheduler // at least has visibility into any placements it made to avoid double placement. // The RefreshIndex computed by evaluatePlan may be stale due to evaluation // against an optimistic copy of the state. if result.RefreshIndex != 0 { result.RefreshIndex = maxUint64(result.RefreshIndex, result.AllocIndex) } pending.respond(result, nil) }
// SubmitPlan is used to handle plan submission func (h *Harness) SubmitPlan(plan *structs.Plan) (*structs.PlanResult, State, error) { // Ensure sequential plan application h.planLock.Lock() defer h.planLock.Unlock() // Store the plan h.Plans = append(h.Plans, plan) // Check for custom planner if h.Planner != nil { return h.Planner.SubmitPlan(plan) } // Get the index index := h.NextIndex() // Prepare the result result := new(structs.PlanResult) result.NodeUpdate = plan.NodeUpdate result.NodeAllocation = plan.NodeAllocation result.AllocIndex = index // Flatten evicts and allocs var allocs []*structs.Allocation for _, updateList := range plan.NodeUpdate { allocs = append(allocs, updateList...) } for _, allocList := range plan.NodeAllocation { allocs = append(allocs, allocList...) } allocs = append(allocs, plan.FailedAllocs...) // Apply the full plan err := h.State.UpsertAllocs(index, allocs) return result, nil, err }