Convert NodeLabelPresence custom predicate to filter plugin.
This commit is contained in:
@@ -12,6 +12,7 @@ go_library(
|
||||
"//pkg/scheduler/framework/plugins/imagelocality:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/interpodaffinity:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodeaffinity:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodelabel:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodename:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodeports:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodepreferavoidpods:go_default_library",
|
||||
@@ -26,6 +27,7 @@ go_library(
|
||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||
"//pkg/scheduler/volumebinder:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -45,6 +47,7 @@ filegroup(
|
||||
"//pkg/scheduler/framework/plugins/interpodaffinity:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/migration:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodeaffinity:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodelabel:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodename:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodeports:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodepreferavoidpods:all-srcs",
|
||||
|
@@ -17,15 +17,18 @@ limitations under the License.
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodelabel"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodepreferavoidpods"
|
||||
@@ -46,9 +49,9 @@ type RegistryArgs struct {
|
||||
VolumeBinder *volumebinder.VolumeBinder
|
||||
}
|
||||
|
||||
// NewDefaultRegistry builds a default registry with all the default plugins.
|
||||
// This is the registry that Kubernetes default scheduler uses. A scheduler that
|
||||
// runs custom plugins, can pass a different Registry when initializing the scheduler.
|
||||
// NewDefaultRegistry builds the default registry with all the in-tree plugins.
|
||||
// This is the registry that Kubernetes default scheduler uses. A scheduler that runs out of tree
|
||||
// plugins can register additional plugins through the WithFrameworkOutOfTreeRegistry option.
|
||||
func NewDefaultRegistry(args *RegistryArgs) framework.Registry {
|
||||
return framework.Registry{
|
||||
imagelocality.Name: imagelocality.New,
|
||||
@@ -74,6 +77,7 @@ func NewDefaultRegistry(args *RegistryArgs) framework.Registry {
|
||||
nodevolumelimits.AzureDiskName: nodevolumelimits.NewAzureDisk,
|
||||
nodevolumelimits.CinderName: nodevolumelimits.NewCinder,
|
||||
interpodaffinity.Name: interpodaffinity.New,
|
||||
nodelabel.Name: nodelabel.New,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +87,8 @@ func NewDefaultRegistry(args *RegistryArgs) framework.Registry {
|
||||
type ConfigProducerArgs struct {
|
||||
// Weight used for priority functions.
|
||||
Weight int32
|
||||
// NodeLabelArgs is the args for the NodeLabel plugin.
|
||||
NodeLabelArgs *nodelabel.Args
|
||||
}
|
||||
|
||||
// ConfigProducer produces a framework's configuration.
|
||||
@@ -191,6 +197,22 @@ func NewDefaultConfigProducerRegistry() *ConfigProducerRegistry {
|
||||
plugins.Filter = appendToPluginSet(plugins.Filter, podtopologyspread.Name, nil)
|
||||
return
|
||||
})
|
||||
registry.RegisterPredicate(nodelabel.Name,
|
||||
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
|
||||
plugins.Filter = appendToPluginSet(plugins.Filter, nodelabel.Name, nil)
|
||||
encoding, err := json.Marshal(args.NodeLabelArgs)
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to marshal %+v", args.NodeLabelArgs)
|
||||
return
|
||||
}
|
||||
config := config.PluginConfig{
|
||||
Name: nodelabel.Name,
|
||||
Args: runtime.Unknown{Raw: encoding},
|
||||
}
|
||||
pluginConfig = append(pluginConfig, config)
|
||||
return
|
||||
})
|
||||
|
||||
// Register Priorities.
|
||||
registry.RegisterPriority(priorities.TaintTolerationPriority,
|
||||
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
|
||||
|
43
pkg/scheduler/framework/plugins/nodelabel/BUILD
Normal file
43
pkg/scheduler/framework/plugins/nodelabel/BUILD
Normal file
@@ -0,0 +1,43 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["node_label.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodelabel",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/migration:go_default_library",
|
||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||
"//pkg/scheduler/nodeinfo:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["node_label_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||
"//pkg/scheduler/nodeinfo:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
70
pkg/scheduler/framework/plugins/nodelabel/node_label.go
Normal file
70
pkg/scheduler/framework/plugins/nodelabel/node_label.go
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package nodelabel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
|
||||
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
||||
)
|
||||
|
||||
// Name of this plugin.
|
||||
const Name = "NodeLabel"
|
||||
|
||||
// Args holds the args that are used to configure the plugin.
|
||||
type Args struct {
|
||||
// The list of labels that identify node "groups"
|
||||
// All of the labels should be either present (or absent) for the node to be considered a fit for hosting the pod
|
||||
Labels []string `json:"labels,omitempty"`
|
||||
// The boolean flag that indicates whether the labels should be present or absent from the node
|
||||
Presence bool `json:"presence,omitempty"`
|
||||
}
|
||||
|
||||
// New initializes a new plugin and returns it.
|
||||
func New(plArgs *runtime.Unknown, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
||||
args := &Args{}
|
||||
if err := framework.DecodeInto(plArgs, args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &NodeLabel{
|
||||
predicate: predicates.NewNodeLabelPredicate(args.Labels, args.Presence),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NodeLabel checks whether a pod can fit based on the node labels which match a filter that it requests.
|
||||
type NodeLabel struct {
|
||||
predicate predicates.FitPredicate
|
||||
}
|
||||
|
||||
var _ framework.FilterPlugin = &NodeLabel{}
|
||||
|
||||
// Name returns name of the plugin. It is used in logs, etc.
|
||||
func (pl *NodeLabel) Name() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
// Filter invoked at the filter extension point.
|
||||
func (pl *NodeLabel) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *nodeinfo.NodeInfo) *framework.Status {
|
||||
// Note that NodeLabelPredicate doesn't use predicate metadata, hence passing nil here.
|
||||
_, reasons, err := pl.predicate(pod, nil, nodeInfo)
|
||||
return migration.PredicateResultToFrameworkStatus(reasons, err)
|
||||
}
|
88
pkg/scheduler/framework/plugins/nodelabel/node_label_test.go
Normal file
88
pkg/scheduler/framework/plugins/nodelabel/node_label_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package nodelabel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
||||
)
|
||||
|
||||
func TestNodeLabelPresence(t *testing.T) {
|
||||
label := map[string]string{"foo": "bar", "bar": "foo"}
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *v1.Pod
|
||||
rawArgs string
|
||||
res framework.Code
|
||||
}{
|
||||
{
|
||||
name: "label does not match, presence true",
|
||||
rawArgs: `{"labels" : ["baz"], "presence" : true}`,
|
||||
res: framework.UnschedulableAndUnresolvable,
|
||||
},
|
||||
{
|
||||
name: "label does not match, presence false",
|
||||
rawArgs: `{"labels" : ["baz"], "presence" : false}`,
|
||||
res: framework.Success,
|
||||
},
|
||||
{
|
||||
name: "one label matches, presence true",
|
||||
rawArgs: `{"labels" : ["foo", "baz"], "presence" : true}`,
|
||||
res: framework.UnschedulableAndUnresolvable,
|
||||
},
|
||||
{
|
||||
name: "one label matches, presence false",
|
||||
rawArgs: `{"labels" : ["foo", "baz"], "presence" : false}`,
|
||||
res: framework.UnschedulableAndUnresolvable,
|
||||
},
|
||||
{
|
||||
name: "all labels match, presence true",
|
||||
rawArgs: `{"labels" : ["foo", "bar"], "presence" : true}`,
|
||||
res: framework.Success,
|
||||
},
|
||||
{
|
||||
name: "all labels match, presence false",
|
||||
rawArgs: `{"labels" : ["foo", "bar"], "presence" : false}`,
|
||||
res: framework.UnschedulableAndUnresolvable,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
node := v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: label}}
|
||||
nodeInfo := schedulernodeinfo.NewNodeInfo()
|
||||
nodeInfo.SetNode(&node)
|
||||
|
||||
args := &runtime.Unknown{Raw: []byte(test.rawArgs)}
|
||||
p, err := New(args, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create plugin: %v", err)
|
||||
}
|
||||
|
||||
status := p.(framework.FilterPlugin).Filter(context.TODO(), nil, test.pod, nodeInfo)
|
||||
if status.Code() != test.res {
|
||||
t.Errorf("Status mismatch. got: %v, want: %v", status.Code(), test.res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user