Merge pull request #28104 from ping035627/ping035627-patch-4

Automatic merge from submit-queue

SchedulerExtender: add failedPredicateMap in Filter() returns

Fix #25797. modify extender.Filter for adding extenders information to “failedPredicateMap” in findNodesThatFit.
When all the filtered nodes that passed "predicateFuncs" don’t pass the extenders filter, the failedPredicateMap hasn’t the extenders information, should add it, I think. So when the length of the “filteredNodes.Items” is 0, we can know the integral information. (The length of the “filteredNodes.Items” is 0, may be because the extenders filter failed.)
This commit is contained in:
Kubernetes Submit Queue 2016-08-06 20:50:33 -07:00 committed by GitHub
commit 711b63e78b
7 changed files with 40 additions and 16 deletions

View File

@ -26,8 +26,9 @@ import (
// managed by Kubernetes. // managed by Kubernetes.
type SchedulerExtender interface { type SchedulerExtender interface {
// Filter based on extender-implemented predicate functions. The filtered list is // Filter based on extender-implemented predicate functions. The filtered list is
// expected to be a subset of the supplied list. // expected to be a subset of the supplied list. failedNodesMap optionally contains
Filter(pod *api.Pod, nodes []*api.Node) (filteredNodes []*api.Node, err error) // the list of failed nodes and failure reasons.
Filter(pod *api.Pod, nodes []*api.Node) (filteredNodes []*api.Node, failedNodesMap schedulerapi.FailedNodesMap, err error)
// Prioritize based on extender-implemented priority functions. The returned scores & weight // Prioritize based on extender-implemented priority functions. The returned scores & weight
// are used to compute the weighted score for an extender. The weighted scores are added to // are used to compute the weighted score for an extender. The weighted scores are added to

View File

@ -139,10 +139,15 @@ type ExtenderArgs struct {
Nodes api.NodeList `json:"nodes"` Nodes api.NodeList `json:"nodes"`
} }
// FailedNodesMap represents the filtered out nodes, with node names and failure messages
type FailedNodesMap map[string]string
// ExtenderFilterResult represents the results of a filter call to an extender // ExtenderFilterResult represents the results of a filter call to an extender
type ExtenderFilterResult struct { type ExtenderFilterResult struct {
// Filtered set of nodes where the pod can be scheduled // Filtered set of nodes where the pod can be scheduled
Nodes api.NodeList `json:"nodes,omitempty"` Nodes api.NodeList `json:"nodes,omitempty"`
// Filtered out nodes where the pod can't be scheduled and the failure messages
FailedNodes FailedNodesMap `json:"failedNodes,omitempty"`
// Error message indicating failure // Error message indicating failure
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
} }

View File

@ -139,10 +139,15 @@ type ExtenderArgs struct {
Nodes apiv1.NodeList `json:"nodes"` Nodes apiv1.NodeList `json:"nodes"`
} }
// FailedNodesMap represents the filtered out nodes, with node names and failure messages
type FailedNodesMap map[string]string
// ExtenderFilterResult represents the results of a filter call to an extender // ExtenderFilterResult represents the results of a filter call to an extender
type ExtenderFilterResult struct { type ExtenderFilterResult struct {
// Filtered set of nodes where the pod can be scheduled // Filtered set of nodes where the pod can be scheduled
Nodes apiv1.NodeList `json:"nodes,omitempty"` Nodes apiv1.NodeList `json:"nodes,omitempty"`
// Filtered out nodes where the pod can't be scheduled and the failure messages
FailedNodes FailedNodesMap `json:"failedNodes,omitempty"`
// Error message indicating failure // Error message indicating failure
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
} }

View File

@ -92,12 +92,13 @@ func NewHTTPExtender(config *schedulerapi.ExtenderConfig, apiVersion string) (al
} }
// Filter based on extender implemented predicate functions. The filtered list is // Filter based on extender implemented predicate functions. The filtered list is
// expected to be a subset of the supplied list. // expected to be a subset of the supplied list. failedNodesMap optionally contains
func (h *HTTPExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, error) { // the list of failed nodes and failure reasons.
func (h *HTTPExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, schedulerapi.FailedNodesMap, error) {
var result schedulerapi.ExtenderFilterResult var result schedulerapi.ExtenderFilterResult
if h.filterVerb == "" { if h.filterVerb == "" {
return nodes, nil return nodes, schedulerapi.FailedNodesMap{}, nil
} }
nodeItems := make([]api.Node, 0, len(nodes)) nodeItems := make([]api.Node, 0, len(nodes))
@ -110,16 +111,17 @@ func (h *HTTPExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, err
} }
if err := h.send(h.filterVerb, &args, &result); err != nil { if err := h.send(h.filterVerb, &args, &result); err != nil {
return nil, err return nil, nil, err
} }
if result.Error != "" { if result.Error != "" {
return nil, fmt.Errorf(result.Error) return nil, nil, fmt.Errorf(result.Error)
} }
nodeResult := make([]*api.Node, 0, len(result.Nodes.Items)) nodeResult := make([]*api.Node, 0, len(result.Nodes.Items))
for i := range result.Nodes.Items { for i := range result.Nodes.Items {
nodeResult = append(nodeResult, &result.Nodes.Items[i]) nodeResult = append(nodeResult, &result.Nodes.Items[i])
} }
return nodeResult, nil return nodeResult, result.FailedNodes, nil
} }
// Prioritize based on extender implemented priority functions. Weight*priority is added // Prioritize based on extender implemented priority functions. Weight*priority is added

View File

@ -107,14 +107,15 @@ type FakeExtender struct {
weight int weight int
} }
func (f *FakeExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, error) { func (f *FakeExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, schedulerapi.FailedNodesMap, error) {
filtered := []*api.Node{} filtered := []*api.Node{}
failedNodesMap := schedulerapi.FailedNodesMap{}
for _, node := range nodes { for _, node := range nodes {
fits := true fits := true
for _, predicate := range f.predicates { for _, predicate := range f.predicates {
fit, err := predicate(pod, node) fit, err := predicate(pod, node)
if err != nil { if err != nil {
return []*api.Node{}, err return []*api.Node{}, schedulerapi.FailedNodesMap{}, err
} }
if !fit { if !fit {
fits = false fits = false
@ -123,9 +124,11 @@ func (f *FakeExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, err
} }
if fits { if fits {
filtered = append(filtered, node) filtered = append(filtered, node)
} else {
failedNodesMap[node.Name] = "FakeExtender failed"
} }
} }
return filtered, nil return filtered, failedNodesMap, nil
} }
func (f *FakeExtender) Prioritize(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, int, error) { func (f *FakeExtender) Prioritize(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, int, error) {

View File

@ -183,10 +183,14 @@ func findNodesThatFit(
if len(filtered) > 0 && len(extenders) != 0 { if len(filtered) > 0 && len(extenders) != 0 {
for _, extender := range extenders { for _, extender := range extenders {
filteredList, err := extender.Filter(pod, filtered) filteredList, failedMap, err := extender.Filter(pod, filtered)
if err != nil { if err != nil {
return []*api.Node{}, FailedPredicateMap{}, err return []*api.Node{}, FailedPredicateMap{}, err
} }
for failedNodeName, failedMsg := range failedMap {
failedPredicateMap[failedNodeName] = failedMsg
}
filtered = filteredList filtered = filteredList
if len(filtered) == 0 { if len(filtered) == 0 {
break break

View File

@ -79,11 +79,12 @@ func (e *Extender) serveHTTP(t *testing.T, w http.ResponseWriter, req *http.Requ
if strings.Contains(req.URL.Path, filter) { if strings.Contains(req.URL.Path, filter) {
resp := &schedulerapi.ExtenderFilterResult{} resp := &schedulerapi.ExtenderFilterResult{}
nodes, err := e.Filter(&args.Pod, &args.Nodes) nodes, failedNodes, err := e.Filter(&args.Pod, &args.Nodes)
if err != nil { if err != nil {
resp.Error = err.Error() resp.Error = err.Error()
} else { } else {
resp.Nodes = *nodes resp.Nodes = *nodes
resp.FailedNodes = failedNodes
} }
if err := encoder.Encode(resp); err != nil { if err := encoder.Encode(resp); err != nil {
@ -102,14 +103,15 @@ func (e *Extender) serveHTTP(t *testing.T, w http.ResponseWriter, req *http.Requ
} }
} }
func (e *Extender) Filter(pod *api.Pod, nodes *api.NodeList) (*api.NodeList, error) { func (e *Extender) Filter(pod *api.Pod, nodes *api.NodeList) (*api.NodeList, schedulerapi.FailedNodesMap, error) {
filtered := []api.Node{} filtered := []api.Node{}
failedNodesMap := schedulerapi.FailedNodesMap{}
for _, node := range nodes.Items { for _, node := range nodes.Items {
fits := true fits := true
for _, predicate := range e.predicates { for _, predicate := range e.predicates {
fit, err := predicate(pod, &node) fit, err := predicate(pod, &node)
if err != nil { if err != nil {
return &api.NodeList{}, err return &api.NodeList{}, schedulerapi.FailedNodesMap{}, err
} }
if !fit { if !fit {
fits = false fits = false
@ -118,9 +120,11 @@ func (e *Extender) Filter(pod *api.Pod, nodes *api.NodeList) (*api.NodeList, err
} }
if fits { if fits {
filtered = append(filtered, node) filtered = append(filtered, node)
} else {
failedNodesMap[node.Name] = fmt.Sprintf("extender failed: %s", e.name)
} }
} }
return &api.NodeList{Items: filtered}, nil return &api.NodeList{Items: filtered}, failedNodesMap, nil
} }
func (e *Extender) Prioritize(pod *api.Pod, nodes *api.NodeList) (*schedulerapi.HostPriorityList, error) { func (e *Extender) Prioritize(pod *api.Pod, nodes *api.NodeList) (*schedulerapi.HostPriorityList, error) {