Skip to content

Commit ce1dea2

Browse files
committed
Moved all configuration loading code to new package
Signed-off-by: Shmuel Kallner <kallner@il.ibm.com>
1 parent df96c24 commit ce1dea2

File tree

2 files changed

+288
-17
lines changed

2 files changed

+288
-17
lines changed

pkg/epp/common/config/configloader.go renamed to pkg/epp/common/config/loader/configloader.go

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package config
17+
package loader
1818

1919
import (
2020
"errors"
@@ -25,8 +25,11 @@ import (
2525
"k8s.io/apimachinery/pkg/runtime/serializer"
2626
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2727

28+
"sigs.k8s.io/gateway-api-inference-extension/api/config/v1alpha1"
2829
configapi "sigs.k8s.io/gateway-api-inference-extension/api/config/v1alpha1"
2930
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/plugins"
31+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling"
32+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework"
3033
)
3134

3235
var scheme = runtime.NewScheme()
@@ -62,19 +65,61 @@ func LoadConfig(configText []byte, fileName string) (*configapi.EndpointPickerCo
6265
return theConfig, nil
6366
}
6467

65-
func LoadPluginReferences(thePlugins []configapi.PluginSpec, handle plugins.Handle) (map[string]plugins.Plugin, error) {
66-
references := map[string]plugins.Plugin{}
68+
func LoadPluginReferences(thePlugins []configapi.PluginSpec, handle plugins.Handle) error {
6769
for _, pluginConfig := range thePlugins {
68-
thePlugin, err := InstantiatePlugin(pluginConfig, handle)
70+
thePlugin, err := instantiatePlugin(pluginConfig, handle)
6971
if err != nil {
70-
return nil, err
72+
return err
7173
}
72-
references[pluginConfig.Name] = thePlugin
74+
handle.Plugins().AddPlugin(pluginConfig.Name, thePlugin)
7375
}
74-
return references, nil
76+
return nil
77+
}
78+
79+
func LoadSchedulerConfig(configProfiles []v1alpha1.SchedulingProfile, handle plugins.Handle) (*scheduling.SchedulerConfig, error) {
80+
81+
var profiles = map[string]*framework.SchedulerProfile{}
82+
83+
for _, configProfile := range configProfiles {
84+
profile := framework.SchedulerProfile{}
85+
86+
for _, plugin := range configProfile.Plugins {
87+
var err error
88+
thePlugin := handle.Plugins().Plugin(plugin.PluginRef)
89+
if theScorer, ok := thePlugin.(framework.Scorer); ok {
90+
if plugin.Weight == nil {
91+
return nil, fmt.Errorf("scorer '%s' is missing a weight", plugin.PluginRef)
92+
}
93+
thePlugin = framework.NewWeightedScorer(theScorer, *plugin.Weight)
94+
}
95+
err = profile.AddPlugins(thePlugin)
96+
if err != nil {
97+
return nil, err
98+
}
99+
}
100+
profiles[configProfile.Name] = &profile
101+
}
102+
103+
var profileHandler framework.ProfileHandler
104+
var profileHandlerName string
105+
106+
for pluginName, thePlugin := range handle.Plugins().GetAllPluginsWithNames() {
107+
if theProfileHandler, ok := thePlugin.(framework.ProfileHandler); ok {
108+
if profileHandler != nil {
109+
return nil, fmt.Errorf("only one profile handler is allowed. Both %s and %s are profile handlers", profileHandlerName, pluginName)
110+
}
111+
profileHandler = theProfileHandler
112+
profileHandlerName = pluginName
113+
}
114+
}
115+
if profileHandler == nil {
116+
return nil, errors.New("no profile handler was specified")
117+
}
118+
119+
return scheduling.NewSchedulerConfig(profileHandler, profiles), nil
75120
}
76121

77-
func InstantiatePlugin(pluginSpec configapi.PluginSpec, handle plugins.Handle) (plugins.Plugin, error) {
122+
func instantiatePlugin(pluginSpec configapi.PluginSpec, handle plugins.Handle) (plugins.Plugin, error) {
78123
factory, ok := plugins.Registry[pluginSpec.PluginName]
79124
if !ok {
80125
return nil, fmt.Errorf("failed to instantiate the plugin. plugin %s not found", pluginSpec.PluginName)

pkg/epp/common/config/configloader_test.go renamed to pkg/epp/common/config/loader/configloader_test.go

Lines changed: 235 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package config
17+
package loader
1818

1919
import (
2020
"context"
@@ -27,7 +27,12 @@ import (
2727
configapi "sigs.k8s.io/gateway-api-inference-extension/api/config/v1alpha1"
2828
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/plugins"
2929
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework"
30+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/filter"
31+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/multi/prefix"
32+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/picker"
33+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/profile"
3034
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/types"
35+
"sigs.k8s.io/gateway-api-inference-extension/test/utils"
3136
)
3237

3338
const (
@@ -175,14 +180,14 @@ func TestLoadConfiguration(t *testing.T) {
175180
{
176181
name: "successFromFile",
177182
configText: "",
178-
configFile: "../../../../test/testdata/configloader_1_test.yaml",
183+
configFile: "../../../../../test/testdata/configloader_1_test.yaml",
179184
want: goodConfig,
180185
wantErr: false,
181186
},
182187
{
183188
name: "noSuchFile",
184189
configText: "",
185-
configFile: "../../../../test/testdata/configloader_error_test.yaml",
190+
configFile: "../../../../../test/testdata/configloader_error_test.yaml",
186191
wantErr: true,
187192
},
188193
}
@@ -210,14 +215,15 @@ func TestLoadPluginReferences(t *testing.T) {
210215
if err != nil {
211216
t.Fatalf("LoadConfig returned unexpected error: %v", err)
212217
}
213-
references, err := LoadPluginReferences(theConfig.Plugins, testHandle{})
218+
handle := utils.NewTestHandle()
219+
err = LoadPluginReferences(theConfig.Plugins, handle)
214220
if err != nil {
215221
t.Fatalf("LoadPluginReferences returned unexpected error: %v", err)
216222
}
217-
if len(references) == 0 {
223+
if len(handle.Plugins().GetAllPlugins()) == 0 {
218224
t.Fatalf("LoadPluginReferences returned an empty set of references")
219225
}
220-
if t1, ok := references["test1"]; !ok {
226+
if t1 := handle.Plugins().Plugin("test1"); t1 == nil {
221227
t.Fatalf("LoadPluginReferences returned references did not contain test1")
222228
} else if _, ok := t1.(*test1); !ok {
223229
t.Fatalf("LoadPluginReferences returned references value for test1 has the wrong type %#v", t1)
@@ -227,21 +233,104 @@ func TestLoadPluginReferences(t *testing.T) {
227233
if err != nil {
228234
t.Fatalf("LoadConfig returned unexpected error: %v", err)
229235
}
230-
_, err = LoadPluginReferences(theConfig.Plugins, testHandle{})
236+
err = LoadPluginReferences(theConfig.Plugins, utils.NewTestHandle())
231237
if err == nil {
232238
t.Fatalf("LoadPluginReferences did not return the expected error")
233239
}
234240
}
235241

236242
func TestInstantiatePlugin(t *testing.T) {
237243
plugSpec := configapi.PluginSpec{PluginName: "plover"}
238-
_, err := InstantiatePlugin(plugSpec, testHandle{})
244+
_, err := instantiatePlugin(plugSpec, utils.NewTestHandle())
239245
if err == nil {
240246
t.Fatalf("InstantiatePlugin did not return the expected error")
241247
}
242248
}
243249

244-
type testHandle struct {
250+
func TestLoadSchedulerConfig(t *testing.T) {
251+
tests := []struct {
252+
name string
253+
configText string
254+
wantErr bool
255+
}{
256+
{
257+
name: "schedulerSuccess",
258+
configText: successSchedulerConfigText,
259+
wantErr: false,
260+
},
261+
{
262+
name: "errorBadPluginJson",
263+
configText: errorBadPluginJsonText,
264+
wantErr: true,
265+
},
266+
{
267+
name: "errorBadReferenceNoWeight",
268+
configText: errorBadReferenceNoWeightText,
269+
wantErr: true,
270+
},
271+
{
272+
name: "errorPluginReferenceJson",
273+
configText: errorPluginReferenceJsonText,
274+
wantErr: true,
275+
},
276+
{
277+
name: "errorTwoPickers",
278+
configText: errorTwoPickersText,
279+
wantErr: true,
280+
},
281+
{
282+
name: "errorConfig",
283+
configText: errorConfigText,
284+
wantErr: true,
285+
},
286+
{
287+
name: "errorTwoProfileHandlers",
288+
configText: errorTwoProfileHandlersText,
289+
wantErr: true,
290+
},
291+
{
292+
name: "errorNoProfileHandlers",
293+
configText: errorNoProfileHandlersText,
294+
wantErr: true,
295+
},
296+
}
297+
298+
registerNeededPlgugins()
299+
300+
for _, test := range tests {
301+
theConfig, err := LoadConfig([]byte(test.configText), "")
302+
if err != nil {
303+
if test.wantErr {
304+
continue
305+
}
306+
t.Fatalf("LoadConfig returned unexpected error: %v", err)
307+
}
308+
handle := utils.NewTestHandle()
309+
err = LoadPluginReferences(theConfig.Plugins, handle)
310+
if err != nil {
311+
if test.wantErr {
312+
continue
313+
}
314+
t.Fatalf("LoadPluginReferences returned unexpected error: %v", err)
315+
}
316+
317+
_, err = LoadSchedulerConfig(theConfig.SchedulingProfiles, handle)
318+
if err != nil {
319+
if !test.wantErr {
320+
t.Errorf("LoadSchedulerConfig returned an unexpected error. error %v", err)
321+
}
322+
} else if test.wantErr {
323+
t.Errorf("LoadSchedulerConfig did not return an expected error (%s)", test.name)
324+
}
325+
}
326+
}
327+
328+
func registerNeededPlgugins() {
329+
plugins.Register(filter.LowQueueFilterType, filter.LowQueueFilterFactory)
330+
plugins.Register(prefix.PrefixCachePluginType, prefix.PrefixCachePluginFactory)
331+
plugins.Register(picker.MaxScorePickerType, picker.MaxScorePickerFactory)
332+
plugins.Register(picker.RandomPickerType, picker.RandomPickerFactory)
333+
plugins.Register(profile.SingleProfileHandlerType, profile.SingleProfileHandlerFactory)
245334
}
246335

247336
// The following multi-line string constants, cause false positive lint errors (dupword)
@@ -545,3 +634,140 @@ func registerTestPlugins() {
545634
},
546635
)
547636
}
637+
638+
//nolint:dupword
639+
const successSchedulerConfigText = `
640+
apiVersion: inference.networking.x-k8s.io/v1alpha1
641+
kind: EndpointPickerConfig
642+
plugins:
643+
- name: lowQueue
644+
pluginName: low-queue
645+
parameters:
646+
threshold: 10
647+
- name: prefixCache
648+
pluginName: prefix-cache
649+
parameters:
650+
hashBlockSize: 32
651+
- name: maxScore
652+
pluginName: max-score
653+
- name: profileHandler
654+
pluginName: single-profile
655+
schedulingProfiles:
656+
- name: default
657+
plugins:
658+
- pluginRef: lowQueue
659+
- pluginRef: prefixCache
660+
weight: 50
661+
- pluginRef: maxScore
662+
`
663+
664+
//nolint:dupword
665+
const errorBadPluginJsonText = `
666+
apiVersion: inference.networking.x-k8s.io/v1alpha1
667+
kind: EndpointPickerConfig
668+
plugins:
669+
- name:profileHandler
670+
pluginName: single-profile
671+
- name: prefixCache
672+
pluginName: prefix-cache
673+
parameters:
674+
hashBlockSize: asdf
675+
schedulingProfiles:
676+
- name: default
677+
plugins:
678+
- pluginRef: prefixCache
679+
weight: 50
680+
`
681+
682+
//nolint:dupword
683+
const errorBadReferenceNoWeightText = `
684+
apiVersion: inference.networking.x-k8s.io/v1alpha1
685+
kind: EndpointPickerConfig
686+
plugins:
687+
- name: profileHandler
688+
pluginName: single-profile
689+
- name: prefixCache
690+
pluginName: prefix-cache
691+
parameters:
692+
hashBlockSize: 32
693+
schedulingProfiles:
694+
- name: default
695+
plugins:
696+
- pluginRef: prefixCache
697+
`
698+
699+
//nolint:dupword
700+
const errorPluginReferenceJsonText = `
701+
apiVersion: inference.networking.x-k8s.io/v1alpha1
702+
kind: EndpointPickerConfig
703+
plugins:
704+
- name: lowQueue
705+
pluginName: low-queue
706+
parameters:
707+
threshold: qwer
708+
- name: profileHandler
709+
pluginName: single-profile
710+
schedulingProfiles:
711+
- name: default
712+
plugins:
713+
- pluginRef: lowQueue
714+
`
715+
716+
//nolint:dupword
717+
const errorTwoPickersText = `
718+
apiVersion: inference.networking.x-k8s.io/v1alpha1
719+
kind: EndpointPickerConfig
720+
plugins:
721+
- name: profileHandler
722+
pluginName: single-profile
723+
- name: maxScore
724+
pluginName: max-score
725+
- name: random
726+
pluginName: random
727+
schedulingProfiles:
728+
- name: default
729+
plugins:
730+
- pluginRef: maxScore
731+
- pluginRef: random
732+
`
733+
734+
//nolint:dupword
735+
const errorConfigText = `
736+
apiVersion: inference.networking.x-k8s.io/v1alpha1
737+
kind: EndpointPickerConfig
738+
plugins:
739+
- name: lowQueue
740+
pluginName: low-queue
741+
parameters:
742+
threshold: 10
743+
`
744+
745+
//nolint:dupword
746+
const errorTwoProfileHandlersText = `
747+
apiVersion: inference.networking.x-k8s.io/v1alpha1
748+
kind: EndpointPickerConfig
749+
plugins:
750+
- name: profileHandler
751+
pluginName: single-profile
752+
- name: secondProfileHandler
753+
pluginName: single-profile
754+
- name: maxScore
755+
pluginName: max-score
756+
schedulingProfiles:
757+
- name: default
758+
plugins:
759+
- pluginRef: maxScore
760+
`
761+
762+
//nolint:dupword
763+
const errorNoProfileHandlersText = `
764+
apiVersion: inference.networking.x-k8s.io/v1alpha1
765+
kind: EndpointPickerConfig
766+
plugins:
767+
- name: maxScore
768+
pluginName: max-score
769+
schedulingProfiles:
770+
- name: default
771+
plugins:
772+
- pluginRef: maxScore
773+
`

0 commit comments

Comments
 (0)