Skip to content

Commit bee1a9e

Browse files
author
Adhityaa Chandrasekar
committed
devel/sig-scheduling: add scheduler framework plugins doc
Signed-off-by: Adhityaa Chandrasekar <[email protected]>
1 parent 81ece45 commit bee1a9e

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Scheduler Framework Plugins
2+
3+
## Creating a new in-tree plugin
4+
5+
Read [the docs](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/)
6+
to understand the different extension points within the scheduling framework.
7+
8+
TODO([#5466](https://github.com/kubernetes/community/issues/5466)): finish this section
9+
10+
## Adding plugin configuration parameters through `KubeSchedulerConfiguration`
11+
12+
You can give users the ability to configure parameters in scheduler plugins using
13+
[`KubeSchedulerConfiguration`](https://kubernetes.io/docs/reference/scheduling/config/).
14+
This section covers how you can add arguments to existing in-tree plugins [(example PR)](https://github.com/kubernetes/kubernetes/pull/94814).
15+
Let's assume the plugin is called `FooPlugin` and we want to add an optional
16+
integer parameter named `barParam`.
17+
18+
### Defining and registering the struct
19+
20+
First, we need to define a struct type named `FooPluginArgs` in
21+
`pkg/scheduler/apis/config/types_pluginargs.go`, which is the representation of
22+
the configuration parameters that is internal to the scheduler.
23+
24+
```go
25+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
26+
27+
type FooPluginArgs struct {
28+
// metav1 is k8s.io/apimachinery/pkg/apis/meta/v1 (package is in staging/src)
29+
metav1.TypeMeta
30+
BarParam int32
31+
}
32+
```
33+
34+
Note that we embed `k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta` to include
35+
API metadata for [versioning and persistence](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#api-conventions).
36+
We add the `+k8s:deepcopy-gen:interfaces` comment to [auto-generate a `DeepCopy` function](https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/code-generator)
37+
for the struct.
38+
39+
Similarly, define `FooPluginArgs` in `staging/src/k8s.io/kube-scheduler/config/{version}/types_pluginargs.go`,
40+
which is the versioned representation used in the `kube-scheduler` binary used
41+
for deserialization. This time, however, in order to allow implicit default
42+
values for arguments, the type of the struct's fields may be pointers; leaving
43+
a parameter unspecified will set the pointer field to its zero value (nil),
44+
which can be used to let the framework know that it must fill in the default
45+
value. `BarParam` is of type `int32` and let's say we want a non-zero default
46+
value for it:
47+
48+
```go
49+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
50+
51+
type FooPluginArgs struct {
52+
metav1.TypeMeta `json:",inline"`
53+
BarParam *int32 `json:"barParam,omitempty"`
54+
}
55+
```
56+
57+
For each `types_pluginargs.go` addition, remember to register the type in the
58+
corresponding `register.go`, which will allow the scheduler to recognize
59+
`KubeSchedulerConfiguration` values at parse-time.
60+
61+
### Setting defaults
62+
63+
When a `KubeSchedulerConfiguration` object is parsed (happens in
64+
`cmd/kube-scheduler/app/options/options.go`), the scheduler will convert from
65+
the versioned type to the internal type, filling in the unspecified fields with
66+
defaults. Speaking of defaults, define `SetDefaults_FooPluginArgs` in
67+
`pkg/scheduler/apis/config/v1beta1/defaults.go` as follows:
68+
69+
```go
70+
// v1beta1 refers to k8s.io/kube-scheduler/config/v1beta1 (package is in staging/src)
71+
func SetDefaults_FooPluginArgs(obj *v1beta1.FooPluginArgs) {
72+
if obj.BarParam == nil {
73+
obj.BarParam = pointer.Int32Ptr(42)
74+
}
75+
}
76+
```
77+
78+
### Validating configuration at runtime
79+
80+
Next, we need to define validators to make sure the user's configuration and
81+
your default values are valid. To do this, add something like this in
82+
`pkg/scheduler/apis/config/validation/validation_pluginargs.go`:
83+
84+
```go
85+
// From here on, FooPluginArgs refers to the type defined in pkg/scheduler
86+
// definition, not the kube-scheduler definition. We're dealing with
87+
// post-default values.
88+
func ValidateFooPluginArgs(args config.FooPluginArgs) error {
89+
if args.BarParam < 0 && args.BarParam > 100 {
90+
return fmt.Errorf("must be in the range [0, 100]")
91+
}
92+
return nil
93+
}
94+
```
95+
96+
### Code generation
97+
98+
We have defined everything necessary to run code generation now. Remember to
99+
commit all your changes (not sure why this is needed) and do a `make clean`
100+
first. Then:
101+
102+
```sh
103+
$ cd $GOPATH/src/k8s.io/kubernetes
104+
$ git add -A && git commit
105+
$ make clean
106+
$ ./hack/update-codegen.sh
107+
$ make generated_files
108+
```
109+
110+
This should automatically generate code to deep copy objects, convert between
111+
different struct types, convert pointer types to raw types, and set defaults.
112+
113+
### Testing
114+
115+
After code generation, go back and write tests for all of the changes you made
116+
in the previous section:
117+
118+
- `pkg/scheduler/apis/config/v1beta1/defaults_test.go` to unit test the
119+
defaults.
120+
- `pkg/scheduler/apis/config/validation/validation_pluginargs_test.go` to unit
121+
test the validator.
122+
- `pkg/scheduler/apis/config/scheme/scheme_test.go` to test the whole pipeline
123+
using a `KubeSchedulerConfiguration` definition.
124+
125+
### Receiving the arguments in the plugin
126+
127+
We can now finally receive `FooPluginArgs` in the plugin code. To do this,
128+
modify the plugin's `New` method signature like so:
129+
130+
```go
131+
func New(fpArgs runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
132+
// config.FooPluginArgs refers to the pkg/scheduler struct type definition.
133+
args, ok := fpArgs.(*config.FooPluginArgs)
134+
if !ok {
135+
return nil, fmt.Errorf("got args of type %T, want *FooPluginArgs", fpArgs)
136+
}
137+
if err := validation.ValidateFooPluginArgs(*args); err != nil {
138+
return nil, err
139+
}
140+
// Use args.BarParam as you like.
141+
}
142+
```

0 commit comments

Comments
 (0)