Skip to content

Commit b632ead

Browse files
authored
Merge pull request kubernetes#86446 from ahg-g/ahg1-nodelabel
Move NodeLabel priority logic to its Score and Filter plugin
2 parents 641d029 + 68f3802 commit b632ead

File tree

7 files changed

+51
-213
lines changed

7 files changed

+51
-213
lines changed

pkg/scheduler/algorithm/predicates/predicates.go

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -939,59 +939,6 @@ func PodFitsHost(pod *v1.Pod, meta Metadata, nodeInfo *schedulernodeinfo.NodeInf
939939
return false, []PredicateFailureReason{ErrPodNotMatchHostName}, nil
940940
}
941941

942-
// NodeLabelChecker contains information to check node labels for a predicate.
943-
type NodeLabelChecker struct {
944-
// presentLabels should be present for the node to be considered a fit for hosting the pod
945-
presentLabels []string
946-
// absentLabels should be absent for the node to be considered a fit for hosting the pod
947-
absentLabels []string
948-
}
949-
950-
// NewNodeLabelPredicate creates a predicate which evaluates whether a pod can fit based on the
951-
// node labels which match a filter that it requests.
952-
func NewNodeLabelPredicate(presentLabels []string, absentLabels []string) FitPredicate {
953-
labelChecker := &NodeLabelChecker{
954-
presentLabels: presentLabels,
955-
absentLabels: absentLabels,
956-
}
957-
return labelChecker.CheckNodeLabelPresence
958-
}
959-
960-
// CheckNodeLabelPresence checks whether all of the specified labels exists on a node or not, regardless of their value
961-
// If "presence" is false, then returns false if any of the requested labels matches any of the node's labels,
962-
// otherwise returns true.
963-
// If "presence" is true, then returns false if any of the requested labels does not match any of the node's labels,
964-
// otherwise returns true.
965-
//
966-
// Consider the cases where the nodes are placed in regions/zones/racks and these are identified by labels
967-
// In some cases, it is required that only nodes that are part of ANY of the defined regions/zones/racks be selected
968-
//
969-
// Alternately, eliminating nodes that have a certain label, regardless of value, is also useful
970-
// A node may have a label with "retiring" as key and the date as the value
971-
// and it may be desirable to avoid scheduling new pods on this node.
972-
func (n *NodeLabelChecker) CheckNodeLabelPresence(pod *v1.Pod, meta Metadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
973-
node := nodeInfo.Node()
974-
if node == nil {
975-
return false, nil, fmt.Errorf("node not found")
976-
}
977-
978-
nodeLabels := labels.Set(node.Labels)
979-
check := func(labels []string, presence bool) bool {
980-
for _, label := range labels {
981-
exists := nodeLabels.Has(label)
982-
if (exists && !presence) || (!exists && presence) {
983-
return false
984-
}
985-
}
986-
return true
987-
}
988-
if check(n.presentLabels, true) && check(n.absentLabels, false) {
989-
return true, nil, nil
990-
}
991-
992-
return false, []PredicateFailureReason{ErrNodeLabelPresenceViolated}, nil
993-
}
994-
995942
// PodFitsHostPorts is a wrapper around PodFitsHostPortsPredicate. This is needed until
996943
// we are able to get rid of the FitPredicate function signature.
997944
// TODO(#85822): remove this function once predicate registration logic is deleted.

pkg/scheduler/algorithm/predicates/predicates_test.go

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,69 +1651,6 @@ func TestPodFitsSelector(t *testing.T) {
16511651
}
16521652
}
16531653

1654-
func TestNodeLabelPresence(t *testing.T) {
1655-
label := map[string]string{"foo": "bar", "bar": "foo"}
1656-
tests := []struct {
1657-
pod *v1.Pod
1658-
presentLabels []string
1659-
absentLabels []string
1660-
fits bool
1661-
name string
1662-
}{
1663-
{
1664-
presentLabels: []string{"baz"},
1665-
fits: false,
1666-
name: "label does not match, presence true",
1667-
},
1668-
{
1669-
absentLabels: []string{"baz"},
1670-
fits: true,
1671-
name: "label does not match, presence false",
1672-
},
1673-
{
1674-
presentLabels: []string{"foo", "baz"},
1675-
fits: false,
1676-
name: "one label matches, presence true",
1677-
},
1678-
{
1679-
absentLabels: []string{"foo", "baz"},
1680-
fits: false,
1681-
name: "one label matches, presence false",
1682-
},
1683-
{
1684-
presentLabels: []string{"foo", "bar"},
1685-
fits: true,
1686-
name: "all labels match, presence true",
1687-
},
1688-
{
1689-
absentLabels: []string{"foo", "bar"},
1690-
fits: false,
1691-
name: "all labels match, presence false",
1692-
},
1693-
}
1694-
expectedFailureReasons := []PredicateFailureReason{ErrNodeLabelPresenceViolated}
1695-
1696-
for _, test := range tests {
1697-
t.Run(test.name, func(t *testing.T) {
1698-
node := v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: label}}
1699-
nodeInfo := schedulernodeinfo.NewNodeInfo()
1700-
nodeInfo.SetNode(&node)
1701-
1702-
labelChecker := NodeLabelChecker{test.presentLabels, test.absentLabels}
1703-
fits, reasons, err := labelChecker.CheckNodeLabelPresence(test.pod, nil, nodeInfo)
1704-
if err != nil {
1705-
t.Errorf("unexpected error: %v", err)
1706-
}
1707-
if !fits && !reflect.DeepEqual(reasons, expectedFailureReasons) {
1708-
t.Errorf("unexpected failure reasons: %v, want: %v", reasons, expectedFailureReasons)
1709-
}
1710-
if fits != test.fits {
1711-
t.Errorf("expected: %v got %v", test.fits, fits)
1712-
}
1713-
})
1714-
}
1715-
}
1716-
17171654
func newPodWithPort(hostPorts ...int) *v1.Pod {
17181655
networkPorts := []v1.ContainerPort{}
17191656
for _, port := range hostPorts {

pkg/scheduler/algorithm/priorities/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ go_library(
1616
"metadata.go",
1717
"most_requested.go",
1818
"node_affinity.go",
19-
"node_label.go",
2019
"node_prefer_avoid_pods.go",
2120
"priorities.go",
2221
"reduce.go",

pkg/scheduler/algorithm/priorities/node_label.go

Lines changed: 0 additions & 70 deletions
This file was deleted.

pkg/scheduler/algorithm_factory.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,7 @@ func RegisterCustomFitPredicate(policy schedulerapi.PredicatePolicy, pluginArgs
278278
pluginArgs.NodeLabelArgs.AbsentLabels = append(pluginArgs.NodeLabelArgs.AbsentLabels, policy.Argument.LabelsPresence.Labels...)
279279
}
280280
predicateFactory = func(_ AlgorithmFactoryArgs) predicates.FitPredicate {
281-
return predicates.NewNodeLabelPredicate(
282-
pluginArgs.NodeLabelArgs.PresentLabels,
283-
pluginArgs.NodeLabelArgs.AbsentLabels,
284-
)
281+
return nil
285282
}
286283
}
287284
} else if predicateFactory, ok = fitPredicateMap[policyName]; ok {
@@ -399,10 +396,7 @@ func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy, configPr
399396
schedulerFactoryMutex.RUnlock()
400397
pcf = &PriorityConfigFactory{
401398
MapReduceFunction: func(_ AlgorithmFactoryArgs) (priorities.PriorityMapFunction, priorities.PriorityReduceFunction) {
402-
return priorities.NewNodeLabelPriority(
403-
configProducerArgs.NodeLabelArgs.PresentLabelsPreference,
404-
configProducerArgs.NodeLabelArgs.AbsentLabelsPreference,
405-
)
399+
return nil, nil
406400
},
407401
Weight: weight,
408402
}

pkg/scheduler/framework/plugins/nodelabel/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ go_library(
77
visibility = ["//visibility:public"],
88
deps = [
99
"//pkg/scheduler/algorithm/predicates:go_default_library",
10-
"//pkg/scheduler/algorithm/priorities:go_default_library",
1110
"//pkg/scheduler/framework/plugins/migration:go_default_library",
1211
"//pkg/scheduler/framework/v1alpha1:go_default_library",
1312
"//pkg/scheduler/nodeinfo:go_default_library",
1413
"//staging/src/k8s.io/api/core/v1:go_default_library",
14+
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
1515
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
1616
],
1717
)

pkg/scheduler/framework/plugins/nodelabel/node_label.go

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121
"fmt"
2222

2323
v1 "k8s.io/api/core/v1"
24+
"k8s.io/apimachinery/pkg/labels"
2425
"k8s.io/apimachinery/pkg/runtime"
2526
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
26-
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
2727
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
2828
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
2929
"k8s.io/kubernetes/pkg/scheduler/nodeinfo"
@@ -60,8 +60,8 @@ func validateNoConflict(presentLabels []string, absentLabels []string) error {
6060

6161
// New initializes a new plugin and returns it.
6262
func New(plArgs *runtime.Unknown, handle framework.FrameworkHandle) (framework.Plugin, error) {
63-
args := &Args{}
64-
if err := framework.DecodeInto(plArgs, args); err != nil {
63+
args := Args{}
64+
if err := framework.DecodeInto(plArgs, &args); err != nil {
6565
return nil, err
6666
}
6767
if err := validateNoConflict(args.PresentLabels, args.AbsentLabels); err != nil {
@@ -70,20 +70,16 @@ func New(plArgs *runtime.Unknown, handle framework.FrameworkHandle) (framework.P
7070
if err := validateNoConflict(args.PresentLabelsPreference, args.AbsentLabelsPreference); err != nil {
7171
return nil, err
7272
}
73-
// Note that the reduce function is always nil therefore it's ignored.
74-
prioritize, _ := priorities.NewNodeLabelPriority(args.PresentLabelsPreference, args.AbsentLabelsPreference)
7573
return &NodeLabel{
76-
handle: handle,
77-
predicate: predicates.NewNodeLabelPredicate(args.PresentLabels, args.AbsentLabels),
78-
prioritize: prioritize,
74+
handle: handle,
75+
Args: args,
7976
}, nil
8077
}
8178

8279
// NodeLabel checks whether a pod can fit based on the node labels which match a filter that it requests.
8380
type NodeLabel struct {
84-
handle framework.FrameworkHandle
85-
predicate predicates.FitPredicate
86-
prioritize priorities.PriorityMapFunction
81+
handle framework.FrameworkHandle
82+
Args
8783
}
8884

8985
var _ framework.FilterPlugin = &NodeLabel{}
@@ -95,10 +91,31 @@ func (pl *NodeLabel) Name() string {
9591
}
9692

9793
// Filter invoked at the filter extension point.
94+
// It checks whether all of the specified labels exists on a node or not, regardless of their value
95+
//
96+
// Consider the cases where the nodes are placed in regions/zones/racks and these are identified by labels
97+
// In some cases, it is required that only nodes that are part of ANY of the defined regions/zones/racks be selected
98+
//
99+
// Alternately, eliminating nodes that have a certain label, regardless of value, is also useful
100+
// A node may have a label with "retiring" as key and the date as the value
101+
// and it may be desirable to avoid scheduling new pods on this node.
98102
func (pl *NodeLabel) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *nodeinfo.NodeInfo) *framework.Status {
99-
// Note that NodeLabelPredicate doesn't use predicate metadata, hence passing nil here.
100-
_, reasons, err := pl.predicate(pod, nil, nodeInfo)
101-
return migration.PredicateResultToFrameworkStatus(reasons, err)
103+
node := nodeInfo.Node()
104+
nodeLabels := labels.Set(node.Labels)
105+
check := func(labels []string, presence bool) bool {
106+
for _, label := range labels {
107+
exists := nodeLabels.Has(label)
108+
if (exists && !presence) || (!exists && presence) {
109+
return false
110+
}
111+
}
112+
return true
113+
}
114+
if check(pl.PresentLabels, true) && check(pl.AbsentLabels, false) {
115+
return nil
116+
}
117+
118+
return migration.PredicateResultToFrameworkStatus([]predicates.PredicateFailureReason{predicates.ErrNodeLabelPresenceViolated}, nil)
102119
}
103120

104121
// Score invoked at the score extension point.
@@ -107,9 +124,23 @@ func (pl *NodeLabel) Score(ctx context.Context, state *framework.CycleState, pod
107124
if err != nil {
108125
return 0, framework.NewStatus(framework.Error, fmt.Sprintf("getting node %q from Snapshot: %v", nodeName, err))
109126
}
110-
// Note that node label priority function doesn't use metadata, hence passing nil here.
111-
s, err := pl.prioritize(pod, nil, nodeInfo)
112-
return s.Score, migration.ErrorToFrameworkStatus(err)
127+
128+
node := nodeInfo.Node()
129+
score := int64(0)
130+
for _, label := range pl.PresentLabelsPreference {
131+
if labels.Set(node.Labels).Has(label) {
132+
score += framework.MaxNodeScore
133+
}
134+
}
135+
for _, label := range pl.AbsentLabelsPreference {
136+
if !labels.Set(node.Labels).Has(label) {
137+
score += framework.MaxNodeScore
138+
}
139+
}
140+
// Take average score for each label to ensure the score doesn't exceed MaxNodeScore.
141+
score /= int64(len(pl.PresentLabelsPreference) + len(pl.AbsentLabelsPreference))
142+
143+
return score, nil
113144
}
114145

115146
// ScoreExtensions of the Score plugin.

0 commit comments

Comments
 (0)