|
| 1 | +package api |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "sort" |
| 6 | + "strings" |
| 7 | + |
| 8 | + "k8s.io/kubernetes/pkg/scheduler/algorithm" |
| 9 | +) |
| 10 | + |
| 11 | +const ( |
| 12 | + // NodePodNumberExceeded means pods in node exceed the allocatable pod number |
| 13 | + NodePodNumberExceeded = "node(s) pod number exceeded" |
| 14 | + // NodeResourceFitFailed means node could not fit the request of pod |
| 15 | + NodeResourceFitFailed = "node(s) resource fit failed" |
| 16 | + |
| 17 | + // AllNodeUnavailableMsg is the default error message |
| 18 | + AllNodeUnavailableMsg = "all nodes are unavailable" |
| 19 | +) |
| 20 | + |
| 21 | +// FitErrors is set of FitError on many nodes |
| 22 | +type FitErrors struct { |
| 23 | + nodes map[string]*FitError |
| 24 | + err string |
| 25 | +} |
| 26 | + |
| 27 | +// NewFitErrors returns an FitErrors |
| 28 | +func NewFitErrors() *FitErrors { |
| 29 | + f := new(FitErrors) |
| 30 | + f.nodes = make(map[string]*FitError) |
| 31 | + return f |
| 32 | +} |
| 33 | + |
| 34 | +// SetError set the common error message in FitErrors |
| 35 | +func (f *FitErrors) SetError(err string) { |
| 36 | + f.err = err |
| 37 | +} |
| 38 | + |
| 39 | +// SetNodeError set the node error in FitErrors |
| 40 | +func (f *FitErrors) SetNodeError(nodeName string, err error) { |
| 41 | + var fe *FitError |
| 42 | + switch obj := err.(type) { |
| 43 | + case *FitError: |
| 44 | + obj.NodeName = nodeName |
| 45 | + fe = obj |
| 46 | + default: |
| 47 | + fe = &FitError{ |
| 48 | + NodeName: nodeName, |
| 49 | + Reasons: []string{obj.Error()}, |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + f.nodes[nodeName] = fe |
| 54 | +} |
| 55 | + |
| 56 | +// Error returns the final error message |
| 57 | +func (f *FitErrors) Error() string { |
| 58 | + reasons := make(map[string]int) |
| 59 | + |
| 60 | + for _, node := range f.nodes { |
| 61 | + for _, reason := range node.Reasons { |
| 62 | + reasons[reason]++ |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + sortReasonsHistogram := func() []string { |
| 67 | + reasonStrings := []string{} |
| 68 | + for k, v := range reasons { |
| 69 | + reasonStrings = append(reasonStrings, fmt.Sprintf("%v %v", v, k)) |
| 70 | + } |
| 71 | + sort.Strings(reasonStrings) |
| 72 | + return reasonStrings |
| 73 | + } |
| 74 | + if f.err == "" { |
| 75 | + f.err = AllNodeUnavailableMsg |
| 76 | + } |
| 77 | + reasonMsg := fmt.Sprintf(f.err+": %v.", strings.Join(sortReasonsHistogram(), ", ")) |
| 78 | + return reasonMsg |
| 79 | +} |
| 80 | + |
| 81 | +// FitError describe the reason why task could not fit that node |
| 82 | +type FitError struct { |
| 83 | + taskNamespace string |
| 84 | + taskName string |
| 85 | + NodeName string |
| 86 | + Reasons []string |
| 87 | +} |
| 88 | + |
| 89 | +// NewFitError return FitError by message |
| 90 | +func NewFitError(task *TaskInfo, node *NodeInfo, message ...string) *FitError { |
| 91 | + fe := &FitError{ |
| 92 | + taskName: task.Name, |
| 93 | + taskNamespace: task.Namespace, |
| 94 | + NodeName: node.Name, |
| 95 | + Reasons: message, |
| 96 | + } |
| 97 | + return fe |
| 98 | +} |
| 99 | + |
| 100 | +// NewFitErrorByReasons return FitError by reasons |
| 101 | +func NewFitErrorByReasons(task *TaskInfo, node *NodeInfo, reasons ...algorithm.PredicateFailureReason) *FitError { |
| 102 | + message := make([]string, 0, len(reasons)) |
| 103 | + for _, reason := range reasons { |
| 104 | + message = append(message, reason.GetReason()) |
| 105 | + } |
| 106 | + return NewFitError(task, node, message...) |
| 107 | +} |
| 108 | + |
| 109 | +// Error returns the final error message |
| 110 | +func (f *FitError) Error() string { |
| 111 | + return fmt.Sprintf("task %s/%s on node %s fit failed: %s", f.taskNamespace, f.taskName, f.NodeName, strings.Join(f.Reasons, ", ")) |
| 112 | +} |
0 commit comments