func()

in pkg/scheduler/objects/application.go [1441:1539]


func (sa *Application) tryNodes(ask *Allocation, iterator NodeIterator) *AllocationResult {
	var nodeToReserve *Node
	scoreReserved := math.Inf(1)
	// check if the alloc is reserved or not
	allocKey := ask.GetAllocationKey()
	reserved := sa.reservations[allocKey]
	var allocResult *AllocationResult
	var predicateErrors map[string]int
	iterator.ForEachNode(func(node *Node) bool {
		// skip the node if the node is not schedulable
		if !node.IsSchedulable() {
			log.Log(log.SchedApplication).Debug("skipping node for ask as state is unschedulable",
				zap.String("allocationKey", allocKey),
				zap.String("node", node.NodeID))
			return true
		}
		// skip over the node if the resource does not fit the node at all.
		if !node.FitInNode(ask.GetAllocatedResource()) {
			return true
		}
		tryNodeStart := time.Now()
		result, err := sa.tryNode(node, ask)
		if err != nil {
			if predicateErrors == nil {
				predicateErrors = make(map[string]int)
			}
			predicateErrors[err.Error()]++
		}
		// allocation worked so return
		if result != nil {
			metrics.GetSchedulerMetrics().ObserveTryNodeLatency(tryNodeStart)
			// check if the alloc had a reservation: if it has set the resultType and return
			if reserved != nil {
				if reserved.nodeID != node.NodeID {
					// we have a different node reserved for this alloc
					log.Log(log.SchedApplication).Debug("allocate picking reserved alloc during non reserved allocate",
						zap.String("appID", sa.ApplicationID),
						zap.String("reserved nodeID", reserved.nodeID),
						zap.String("allocationKey", allocKey))
					result.ReservedNodeID = reserved.nodeID
				} else {
					// NOTE: this is a safeguard as reserved nodes should never be part of the iterator
					log.Log(log.SchedApplication).Debug("allocate found reserved alloc during non reserved allocate",
						zap.String("appID", sa.ApplicationID),
						zap.String("nodeID", node.NodeID),
						zap.String("allocationKey", allocKey))
				}
				result.ResultType = AllocatedReserved
				allocResult = result
				return false
			}
			// nothing reserved just return this as a normal alloc
			allocResult = result
			return false
		}
		// nothing allocated should we look at a reservation?
		askAge := time.Since(ask.GetCreateTime())
		if reserved == nil && askAge > reservationDelay {
			log.Log(log.SchedApplication).Debug("app reservation check",
				zap.String("allocationKey", allocKey),
				zap.Time("createTime", ask.GetCreateTime()),
				zap.Duration("askAge", askAge),
				zap.Duration("reservationDelay", reservationDelay))
			score := node.GetFitInScoreForAvailableResource(ask.GetAllocatedResource())
			// Record the best node so-far to reserve
			if score < scoreReserved {
				scoreReserved = score
				nodeToReserve = node
			}
		}
		return true
	})

	if allocResult != nil {
		return allocResult
	}

	if predicateErrors != nil {
		ask.SendPredicatesFailedEvent(predicateErrors)
	}

	// we have not allocated yet, check if we should reserve
	// NOTE: the node should not be reserved as the iterator filters them but we do not lock the nodes
	if nodeToReserve != nil && !nodeToReserve.IsReserved() {
		log.Log(log.SchedApplication).Debug("found candidate node for app reservation",
			zap.String("appID", sa.ApplicationID),
			zap.String("nodeID", nodeToReserve.NodeID),
			zap.String("allocationKey", allocKey),
			zap.Int("reservations", len(sa.reservations)))
		// skip the node if conditions can not be satisfied
		if nodeToReserve.preReserveConditions(ask) != nil {
			return nil
		}
		// return reservation allocation and mark it as a reservation
		return newReservedAllocationResult(nodeToReserve.NodeID, ask)
	}
	// ask does not fit, skip to next ask
	return nil
}