github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/scheduler/pipeline.go (about)

     1  package scheduler
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/docker/swarmkit/api"
     7  )
     8  
     9  var (
    10  	defaultFilters = []Filter{
    11  		// Always check for readiness first.
    12  		&ReadyFilter{},
    13  		&ResourceFilter{},
    14  		&PluginFilter{},
    15  		&ConstraintFilter{},
    16  		&PlatformFilter{},
    17  		&HostPortFilter{},
    18  		&MaxReplicasFilter{},
    19  	}
    20  )
    21  
    22  type checklistEntry struct {
    23  	f       Filter
    24  	enabled bool
    25  
    26  	// failureCount counts the number of nodes that this filter failed
    27  	// against.
    28  	failureCount int
    29  }
    30  
    31  type checklistByFailures []checklistEntry
    32  
    33  func (c checklistByFailures) Len() int           { return len(c) }
    34  func (c checklistByFailures) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
    35  func (c checklistByFailures) Less(i, j int) bool { return c[i].failureCount < c[j].failureCount }
    36  
    37  // Pipeline runs a set of filters against nodes.
    38  type Pipeline struct {
    39  	// checklist is a slice of filters to run
    40  	checklist []checklistEntry
    41  }
    42  
    43  // NewPipeline returns a pipeline with the default set of filters.
    44  func NewPipeline() *Pipeline {
    45  	p := &Pipeline{}
    46  
    47  	for _, f := range defaultFilters {
    48  		p.checklist = append(p.checklist, checklistEntry{f: f})
    49  	}
    50  
    51  	return p
    52  }
    53  
    54  // Process a node through the filter pipeline.
    55  // Returns true if all filters pass, false otherwise.
    56  func (p *Pipeline) Process(n *NodeInfo) bool {
    57  	for i, entry := range p.checklist {
    58  		if entry.enabled && !entry.f.Check(n) {
    59  			// Immediately stop on first failure.
    60  			p.checklist[i].failureCount++
    61  			return false
    62  		}
    63  	}
    64  	for i := range p.checklist {
    65  		p.checklist[i].failureCount = 0
    66  	}
    67  	return true
    68  }
    69  
    70  // SetTask sets up the filters to process a new task. Once this is called,
    71  // Process can be called repeatedly to try to assign the task various nodes.
    72  func (p *Pipeline) SetTask(t *api.Task) {
    73  	for i := range p.checklist {
    74  		p.checklist[i].enabled = p.checklist[i].f.SetTask(t)
    75  		p.checklist[i].failureCount = 0
    76  	}
    77  }
    78  
    79  // Explain returns a string explaining why a task could not be scheduled.
    80  func (p *Pipeline) Explain() string {
    81  	var explanation string
    82  
    83  	// Sort from most failures to least
    84  
    85  	sortedByFailures := make([]checklistEntry, len(p.checklist))
    86  	copy(sortedByFailures, p.checklist)
    87  	sort.Sort(sort.Reverse(checklistByFailures(sortedByFailures)))
    88  
    89  	for _, entry := range sortedByFailures {
    90  		if entry.failureCount > 0 {
    91  			if len(explanation) > 0 {
    92  				explanation += "; "
    93  			}
    94  			explanation += entry.f.Explain(entry.failureCount)
    95  		}
    96  	}
    97  
    98  	return explanation
    99  }