mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
f2614f2107
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package scheduler
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"github.com/docker/swarmkit/api"
|
|
)
|
|
|
|
var (
|
|
defaultFilters = []Filter{
|
|
// Always check for readiness first.
|
|
&ReadyFilter{},
|
|
&ResourceFilter{},
|
|
|
|
// TODO(stevvooe): Do not filter based on plugins since they are lazy
|
|
// loaded in the engine. We can add this back when we can schedule
|
|
// plugins in the future.
|
|
// &PluginFilter{},
|
|
|
|
&ConstraintFilter{},
|
|
}
|
|
)
|
|
|
|
type checklistEntry struct {
|
|
f Filter
|
|
enabled bool
|
|
|
|
// failureCount counts the number of nodes that this filter failed
|
|
// against.
|
|
failureCount int
|
|
}
|
|
|
|
type checklistByFailures []checklistEntry
|
|
|
|
func (c checklistByFailures) Len() int { return len(c) }
|
|
func (c checklistByFailures) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
|
func (c checklistByFailures) Less(i, j int) bool { return c[i].failureCount < c[j].failureCount }
|
|
|
|
// Pipeline runs a set of filters against nodes.
|
|
type Pipeline struct {
|
|
// checklist is a slice of filters to run
|
|
checklist []checklistEntry
|
|
}
|
|
|
|
// NewPipeline returns a pipeline with the default set of filters.
|
|
func NewPipeline() *Pipeline {
|
|
p := &Pipeline{}
|
|
|
|
for _, f := range defaultFilters {
|
|
p.checklist = append(p.checklist, checklistEntry{f: f})
|
|
}
|
|
|
|
return p
|
|
}
|
|
|
|
// Process a node through the filter pipeline.
|
|
// Returns true if all filters pass, false otherwise.
|
|
func (p *Pipeline) Process(n *NodeInfo) bool {
|
|
for i, entry := range p.checklist {
|
|
if entry.enabled && !entry.f.Check(n) {
|
|
// Immediately stop on first failure.
|
|
p.checklist[i].failureCount++
|
|
return false
|
|
}
|
|
}
|
|
for i := range p.checklist {
|
|
p.checklist[i].failureCount = 0
|
|
}
|
|
return true
|
|
}
|
|
|
|
// SetTask sets up the filters to process a new task. Once this is called,
|
|
// Process can be called repeatedly to try to assign the task various nodes.
|
|
func (p *Pipeline) SetTask(t *api.Task) {
|
|
for i := range p.checklist {
|
|
p.checklist[i].enabled = p.checklist[i].f.SetTask(t)
|
|
p.checklist[i].failureCount = 0
|
|
}
|
|
}
|
|
|
|
// Explain returns a string explaining why a task could not be scheduled.
|
|
func (p *Pipeline) Explain() string {
|
|
var explanation string
|
|
|
|
// Sort from most failures to least
|
|
|
|
sortedByFailures := make([]checklistEntry, len(p.checklist))
|
|
copy(sortedByFailures, p.checklist)
|
|
sort.Sort(sort.Reverse(checklistByFailures(sortedByFailures)))
|
|
|
|
for _, entry := range sortedByFailures {
|
|
if entry.failureCount > 0 {
|
|
if len(explanation) > 0 {
|
|
explanation += "; "
|
|
}
|
|
explanation += entry.f.Explain(entry.failureCount)
|
|
}
|
|
}
|
|
|
|
return explanation
|
|
}
|