Skip to content

Commit 4c7fd64

Browse files
authored
Move filter and scorer plugins registration to a separate file (#729)
* Move filters and scorers registration to filter/scorer specific files * Default scheduler config contains empty list of scorers Signed-off-by: Maya Barnea <[email protected]> * Default plugin is not a scorer any more Signed-off-by: Maya Barnea <[email protected]> * fix scheduler test + lint comments Signed-off-by: Maya Barnea <[email protected]> --------- Signed-off-by: Maya Barnea <[email protected]>
1 parent 9eeb2dc commit 4c7fd64

File tree

4 files changed

+110
-47
lines changed

4 files changed

+110
-47
lines changed

pkg/epp/scheduling/config.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package scheduling
18+
19+
import "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/plugins"
20+
21+
type SchedulerConfig struct {
22+
preSchedulePlugins []plugins.PreSchedule
23+
scorers []plugins.Scorer
24+
filters []plugins.Filter
25+
postSchedulePlugins []plugins.PostSchedule
26+
picker plugins.Picker
27+
}

pkg/epp/scheduling/default_config.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package scheduling
18+
19+
import (
20+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/plugins"
21+
)
22+
23+
var defPlugin = &defaultPlugin{}
24+
25+
var defaultConfig = &SchedulerConfig{
26+
preSchedulePlugins: []plugins.PreSchedule{},
27+
scorers: []plugins.Scorer{},
28+
filters: []plugins.Filter{defPlugin},
29+
postSchedulePlugins: []plugins.PostSchedule{},
30+
picker: defPlugin,
31+
}

pkg/epp/scheduling/scheduler.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,20 @@ var (
6868
)
6969

7070
func NewScheduler(datastore Datastore) *Scheduler {
71-
defaultPlugin := &defaultPlugin{}
71+
return NewSchedulerWithConfig(datastore, defaultConfig)
72+
}
7273

73-
return &Scheduler{
74+
func NewSchedulerWithConfig(datastore Datastore, config *SchedulerConfig) *Scheduler {
75+
scheduler := &Scheduler{
7476
datastore: datastore,
75-
preSchedulePlugins: []plugins.PreSchedule{},
76-
scorers: []plugins.Scorer{},
77-
filters: []plugins.Filter{defaultPlugin},
78-
postSchedulePlugins: []plugins.PostSchedule{},
79-
picker: defaultPlugin,
77+
preSchedulePlugins: config.preSchedulePlugins,
78+
scorers: config.scorers,
79+
filters: config.filters,
80+
postSchedulePlugins: config.postSchedulePlugins,
81+
picker: config.picker,
8082
}
83+
84+
return scheduler
8185
}
8286

8387
type Scheduler struct {

pkg/epp/scheduling/scheduler_test.go

+41-40
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,17 @@ func TestSchedule(t *testing.T) {
220220
},
221221
}
222222

223+
schedConfig := &SchedulerConfig{
224+
preSchedulePlugins: []plugins.PreSchedule{},
225+
scorers: []plugins.Scorer{},
226+
filters: []plugins.Filter{defPlugin},
227+
postSchedulePlugins: []plugins.PostSchedule{},
228+
picker: defPlugin,
229+
}
230+
223231
for _, test := range tests {
224232
t.Run(test.name, func(t *testing.T) {
225-
scheduler := NewScheduler(&fakeDataStore{pods: test.input})
233+
scheduler := NewSchedulerWithConfig(&fakeDataStore{pods: test.input}, schedConfig)
226234
got, err := scheduler.Schedule(context.Background(), test.req)
227235
if test.err != (err != nil) {
228236
t.Errorf("Unexpected error, got %v, want %v", err, test.err)
@@ -257,26 +265,24 @@ func TestSchedulePlugins(t *testing.T) {
257265
}
258266

259267
tests := []struct {
260-
name string
261-
preSchedulePlugins []plugins.PreSchedule
262-
filters []plugins.Filter
263-
scorers []plugins.Scorer
264-
postSchedulePlugins []plugins.PostSchedule
265-
picker plugins.Picker
266-
input []*backendmetrics.FakePodMetrics
267-
wantTargetPod k8stypes.NamespacedName
268-
targetPodScore float64
268+
name string
269+
config SchedulerConfig
270+
input []*backendmetrics.FakePodMetrics
271+
wantTargetPod k8stypes.NamespacedName
272+
targetPodScore float64
269273
// Number of expected pods to score (after filter)
270274
numPodsToScore int
271275
err bool
272276
}{
273277
{
274-
name: "all plugins executed successfully",
275-
preSchedulePlugins: []plugins.PreSchedule{tp1, tp2},
276-
filters: []plugins.Filter{tp1, tp2},
277-
scorers: []plugins.Scorer{tp1, tp2},
278-
postSchedulePlugins: []plugins.PostSchedule{tp1, tp2},
279-
picker: pickerPlugin,
278+
name: "all plugins executed successfully",
279+
config: SchedulerConfig{
280+
preSchedulePlugins: []plugins.PreSchedule{tp1, tp2},
281+
filters: []plugins.Filter{tp1, tp2},
282+
scorers: []plugins.Scorer{tp1, tp2},
283+
postSchedulePlugins: []plugins.PostSchedule{tp1, tp2},
284+
picker: pickerPlugin,
285+
},
280286
input: []*backendmetrics.FakePodMetrics{
281287
{Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod1"}}},
282288
{Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod2"}}},
@@ -288,12 +294,14 @@ func TestSchedulePlugins(t *testing.T) {
288294
err: false,
289295
},
290296
{
291-
name: "filter all",
292-
preSchedulePlugins: []plugins.PreSchedule{tp1, tp2},
293-
filters: []plugins.Filter{tp1, tp_filterAll},
294-
scorers: []plugins.Scorer{tp1, tp2},
295-
postSchedulePlugins: []plugins.PostSchedule{tp1, tp2},
296-
picker: pickerPlugin,
297+
name: "filter all",
298+
config: SchedulerConfig{
299+
preSchedulePlugins: []plugins.PreSchedule{tp1, tp2},
300+
filters: []plugins.Filter{tp1, tp_filterAll},
301+
scorers: []plugins.Scorer{tp1, tp2},
302+
postSchedulePlugins: []plugins.PostSchedule{tp1, tp2},
303+
picker: pickerPlugin,
304+
},
297305
input: []*backendmetrics.FakePodMetrics{
298306
{Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod1"}}},
299307
{Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod2"}}},
@@ -307,29 +315,22 @@ func TestSchedulePlugins(t *testing.T) {
307315
for _, test := range tests {
308316
t.Run(test.name, func(t *testing.T) {
309317
// Reset all plugins before each new test case.
310-
for _, plugin := range test.preSchedulePlugins {
318+
for _, plugin := range test.config.preSchedulePlugins {
311319
plugin.(*TestPlugin).reset()
312320
}
313-
for _, plugin := range test.postSchedulePlugins {
321+
for _, plugin := range test.config.postSchedulePlugins {
314322
plugin.(*TestPlugin).reset()
315323
}
316-
for _, plugin := range test.filters {
324+
for _, plugin := range test.config.filters {
317325
plugin.(*TestPlugin).reset()
318326
}
319-
for _, plugin := range test.scorers {
327+
for _, plugin := range test.config.scorers {
320328
plugin.(*TestPlugin).reset()
321329
}
322-
test.picker.(*TestPlugin).reset()
330+
test.config.picker.(*TestPlugin).reset()
323331

324332
// Initialize the scheduler
325-
scheduler := &Scheduler{
326-
datastore: &fakeDataStore{pods: test.input},
327-
preSchedulePlugins: test.preSchedulePlugins,
328-
filters: test.filters,
329-
scorers: test.scorers,
330-
postSchedulePlugins: test.postSchedulePlugins,
331-
picker: test.picker,
332-
}
333+
scheduler := NewSchedulerWithConfig(&fakeDataStore{pods: test.input}, &test.config)
333334

334335
req := &types.LLMRequest{Model: "test-model"}
335336
got, err := scheduler.Schedule(context.Background(), req)
@@ -355,35 +356,35 @@ func TestSchedulePlugins(t *testing.T) {
355356
}
356357

357358
// Validate plugin execution counts dynamically
358-
for _, plugin := range test.preSchedulePlugins {
359+
for _, plugin := range test.config.preSchedulePlugins {
359360
tp, _ := plugin.(*TestPlugin)
360361
if tp.PreScheduleCallCount != 1 {
361362
t.Errorf("Plugin %s PreSchedule() called %d times, expected 1", tp.NameRes, tp.PreScheduleCallCount)
362363
}
363364
}
364365

365-
for _, plugin := range test.filters {
366+
for _, plugin := range test.config.filters {
366367
tp, _ := plugin.(*TestPlugin)
367368
if tp.FilterCallCount != 1 {
368369
t.Errorf("Plugin %s Filter() called %d times, expected 1", tp.NameRes, tp.FilterCallCount)
369370
}
370371
}
371372

372-
for _, plugin := range test.scorers {
373+
for _, plugin := range test.config.scorers {
373374
tp, _ := plugin.(*TestPlugin)
374375
if tp.ScoreCallCount != test.numPodsToScore {
375376
t.Errorf("Plugin %s Score() called %d times, expected 1", tp.NameRes, tp.ScoreCallCount)
376377
}
377378
}
378379

379-
for _, plugin := range test.postSchedulePlugins {
380+
for _, plugin := range test.config.postSchedulePlugins {
380381
tp, _ := plugin.(*TestPlugin)
381382
if tp.PostScheduleCallCount != 1 {
382383
t.Errorf("Plugin %s PostSchedule() called %d times, expected 1", tp.NameRes, tp.PostScheduleCallCount)
383384
}
384385
}
385386

386-
tp, _ := test.picker.(*TestPlugin)
387+
tp, _ := test.config.picker.(*TestPlugin)
387388
if tp.PickCallCount != 1 {
388389
t.Errorf("Picker plugin %s Pick() called %d times, expected 1", tp.NameRes, tp.PickCallCount)
389390
}

0 commit comments

Comments
 (0)