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 }