diff --git a/pkg/scheduler/framework/v1alpha1/BUILD b/pkg/scheduler/framework/v1alpha1/BUILD index b942588d778..6554c53dd63 100644 --- a/pkg/scheduler/framework/v1alpha1/BUILD +++ b/pkg/scheduler/framework/v1alpha1/BUILD @@ -19,8 +19,10 @@ go_library( "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library", "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", "//vendor/k8s.io/klog:go_default_library", + "//vendor/sigs.k8s.io/yaml:go_default_library", ], ) @@ -43,10 +45,12 @@ go_test( srcs = [ "framework_test.go", "interface_test.go", + "registry_test.go", ], embed = [":go_default_library"], deps = [ "//pkg/scheduler/apis/config:go_default_library", + "//pkg/scheduler/apis/config/scheme: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", diff --git a/pkg/scheduler/framework/v1alpha1/registry.go b/pkg/scheduler/framework/v1alpha1/registry.go index ab92e96865f..c25c3baf23d 100644 --- a/pkg/scheduler/framework/v1alpha1/registry.go +++ b/pkg/scheduler/framework/v1alpha1/registry.go @@ -20,11 +20,30 @@ import ( "fmt" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/json" + "sigs.k8s.io/yaml" ) // PluginFactory is a function that builds a plugin. type PluginFactory = func(configuration *runtime.Unknown, f FrameworkHandle) (Plugin, error) +// DecodeInto decodes configuration whose type is *runtime.Unknown to the interface into. +func DecodeInto(configuration *runtime.Unknown, into interface{}) error { + if configuration == nil { + return nil + } + + switch configuration.ContentType { + // If ContentType is empty, it means ContentTypeJSON by default. + case runtime.ContentTypeJSON, "": + return json.Unmarshal(configuration.Raw, into) + case runtime.ContentTypeYAML: + return yaml.Unmarshal(configuration.Raw, into) + default: + return fmt.Errorf("not supported content type %s", configuration.ContentType) + } +} + // Registry is a collection of all available plugins. The framework uses a // registry to enable and initialize configured plugins. // All plugins must be in the registry before initializing the framework. diff --git a/pkg/scheduler/framework/v1alpha1/registry_test.go b/pkg/scheduler/framework/v1alpha1/registry_test.go new file mode 100644 index 00000000000..17bff96d99b --- /dev/null +++ b/pkg/scheduler/framework/v1alpha1/registry_test.go @@ -0,0 +1,106 @@ +/* +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 v1alpha1 + +import ( + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" +) + +func TestDecodeInto(t *testing.T) { + type PluginFooConfig struct { + FooTest string `json:"foo_test,omitempty"` + } + tests := []struct { + name string + schedulerConfig string + expeted PluginFooConfig + }{ + { + name: "test decode for JSON config", + schedulerConfig: `{ + "kind": "KubeSchedulerConfiguration", + "apiVersion": "kubescheduler.config.k8s.io/v1alpha1", + "plugins": { + "permit": { + "enabled": [ + { + "name": "foo" + } + ] + } + }, + "pluginConfig": [ + { + "name": "foo", + "args": { + "foo_test": "test decode" + } + } + ] + }`, + expeted: PluginFooConfig{ + FooTest: "test decode", + }, + }, + { + name: "test decode for YAML config", + schedulerConfig: ` +apiVersion: kubescheduler.config.k8s.io/v1alpha1 +kind: KubeSchedulerConfiguration +plugins: + permit: + enabled: + - name: foo +pluginConfig: + - name: foo + args: + foo_test: "test decode"`, + expeted: PluginFooConfig{ + FooTest: "test decode", + }, + }, + } + for i, test := range tests { + schedulerConf, err := loadConfig([]byte(test.schedulerConfig)) + if err != nil { + t.Errorf("Test #%v(%s): failed to load scheduler config: %v", i, test.name, err) + } + var pluginFooConf PluginFooConfig + if err := DecodeInto(&schedulerConf.PluginConfig[0].Args, &pluginFooConf); err != nil { + t.Errorf("Test #%v(%s): failed to decode args %+v: %v", + i, test.name, schedulerConf.PluginConfig[0].Args, err) + } + if !reflect.DeepEqual(pluginFooConf, test.expeted) { + t.Errorf("Test #%v(%s): failed to decode plugin config, expected: %+v, got: %+v", + i, test.name, test.expeted, pluginFooConf) + } + } +} + +func loadConfig(data []byte) (*config.KubeSchedulerConfiguration, error) { + configObj := &config.KubeSchedulerConfiguration{} + if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, configObj); err != nil { + return nil, err + } + + return configObj, nil +}