Merge pull request #87853 from alculquicondor/fix/options_test

Do lenient decoding only for kubescheduler.config.k8s.io/v1alpha1
This commit is contained in:
Kubernetes Prow Robot 2020-02-08 14:46:21 -08:00 committed by GitHub
commit a280a967a5
5 changed files with 96 additions and 41 deletions

View File

@ -40,7 +40,7 @@ go_library(
"//staging/src/k8s.io/component-base/cli/flag:go_default_library",
"//staging/src/k8s.io/component-base/codec:go_default_library",
"//staging/src/k8s.io/component-base/config:go_default_library",
"//staging/src/k8s.io/kube-scheduler/config/v1alpha1:go_default_library",
"//staging/src/k8s.io/kube-scheduler/config/v1alpha2:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
@ -73,10 +73,10 @@ go_test(
"//pkg/scheduler/apis/config: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",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/rand:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
"//staging/src/k8s.io/component-base/config:go_default_library",
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],
)

View File

@ -41,9 +41,8 @@ func loadConfigFromFile(file string) (*kubeschedulerconfig.KubeSchedulerConfigur
}
func loadConfig(data []byte) (*kubeschedulerconfig.KubeSchedulerConfiguration, error) {
configObj := &kubeschedulerconfig.KubeSchedulerConfiguration{}
// The UniversalDecoder runs defaulting and returns the internal type by default.
err := runtime.DecodeInto(kubeschedulerscheme.Codecs.UniversalDecoder(), data, configObj)
obj, gvk, err := kubeschedulerscheme.Codecs.UniversalDecoder().Decode(data, nil, nil)
if err != nil {
// Try strict decoding first. If that fails decode with a lenient
// decoder, which has only v1alpha1 registered, and log a warning.
@ -56,18 +55,20 @@ func loadConfig(data []byte) (*kubeschedulerconfig.KubeSchedulerConfiguration, e
_, lenientCodecs, lenientErr := codec.NewLenientSchemeAndCodecs(
kubeschedulerconfig.AddToScheme,
kubeschedulerconfigv1alpha1.AddToScheme,
kubeschedulerconfigv1alpha2.AddToScheme,
)
if lenientErr != nil {
return nil, lenientErr
}
if lenientErr = runtime.DecodeInto(lenientCodecs.UniversalDecoder(), data, configObj); lenientErr != nil {
return nil, fmt.Errorf("failed lenient decoding: %v", err)
obj, gvk, lenientErr = lenientCodecs.UniversalDecoder().Decode(data, nil, nil)
if lenientErr != nil {
return nil, err
}
klog.Warningf("using lenient decoding as strict decoding failed: %v", err)
}
return configObj, nil
if cfgObj, ok := obj.(*kubeschedulerconfig.KubeSchedulerConfiguration); ok {
return cfgObj, nil
}
return nil, fmt.Errorf("couldn't decode as KubeSchedulerConfiguration, got %s: ", gvk)
}
// WriteConfigFile writes the config into the given file name as YAML.

View File

@ -40,7 +40,7 @@ import (
cliflag "k8s.io/component-base/cli/flag"
componentbaseconfig "k8s.io/component-base/config"
"k8s.io/klog"
kubeschedulerconfigv1alpha1 "k8s.io/kube-scheduler/config/v1alpha1"
kubeschedulerconfigv1alpha2 "k8s.io/kube-scheduler/config/v1alpha2"
schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
"k8s.io/kubernetes/pkg/client/leaderelectionconfig"
"k8s.io/kubernetes/pkg/master/ports"
@ -129,10 +129,10 @@ func splitHostIntPort(s string) (string, int, error) {
}
func newDefaultComponentConfig() (*kubeschedulerconfig.KubeSchedulerConfiguration, error) {
cfgv1alpha1 := kubeschedulerconfigv1alpha1.KubeSchedulerConfiguration{}
kubeschedulerscheme.Scheme.Default(&cfgv1alpha1)
versionedCfg := kubeschedulerconfigv1alpha2.KubeSchedulerConfiguration{}
kubeschedulerscheme.Scheme.Default(&versionedCfg)
cfg := kubeschedulerconfig.KubeSchedulerConfiguration{}
if err := kubeschedulerscheme.Scheme.Convert(&cfgv1alpha1, &cfg, nil); err != nil {
if err := kubeschedulerscheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {
return nil, err
}
return &cfg, nil

View File

@ -24,15 +24,14 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"reflect"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/diff"
apiserveroptions "k8s.io/apiserver/pkg/server/options"
componentbaseconfig "k8s.io/component-base/config"
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
@ -73,7 +72,7 @@ func TestSchedulerOptions(t *testing.T) {
configFile := filepath.Join(tmpDir, "scheduler.yaml")
configKubeconfig := filepath.Join(tmpDir, "config.kubeconfig")
if err := ioutil.WriteFile(configFile, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha1
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
@ -103,8 +102,8 @@ users:
t.Fatal(err)
}
oldconfigFile := filepath.Join(tmpDir, "scheduler_old.yaml")
if err := ioutil.WriteFile(oldconfigFile, []byte(fmt.Sprintf(`
oldConfigFile := filepath.Join(tmpDir, "scheduler_old.yaml")
if err := ioutil.WriteFile(oldConfigFile, []byte(fmt.Sprintf(`
apiVersion: componentconfig/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
@ -114,9 +113,9 @@ leaderElection:
t.Fatal(err)
}
invalidconfigFile := filepath.Join(tmpDir, "scheduler_invalid_wrong_api_version.yaml")
if err := ioutil.WriteFile(invalidconfigFile, []byte(fmt.Sprintf(`
apiVersion: componentconfig/v1alpha2
unknownVersionConfig := filepath.Join(tmpDir, "scheduler_invalid_wrong_api_version.yaml")
if err := ioutil.WriteFile(unknownVersionConfig, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/unknown
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
@ -125,8 +124,18 @@ leaderElection:
t.Fatal(err)
}
unknownFieldConfig := filepath.Join(tmpDir, "scheduler_invalid_unknown_field.yaml")
if err := ioutil.WriteFile(unknownFieldConfig, []byte(fmt.Sprintf(`
noVersionConfig := filepath.Join(tmpDir, "scheduler_invalid_no_version.yaml")
if err := ioutil.WriteFile(noVersionConfig, []byte(fmt.Sprintf(`
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
leaderElection:
leaderElect: true`, configKubeconfig)), os.FileMode(0600)); err != nil {
t.Fatal(err)
}
unknownFieldConfigLenient := filepath.Join(tmpDir, "scheduler_invalid_unknown_field_lenient.yaml")
if err := ioutil.WriteFile(unknownFieldConfigLenient, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
@ -137,9 +146,33 @@ foo: bar`, configKubeconfig)), os.FileMode(0600)); err != nil {
t.Fatal(err)
}
unknownFieldConfig := filepath.Join(tmpDir, "scheduler_invalid_unknown_field.yaml")
if err := ioutil.WriteFile(unknownFieldConfig, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
leaderElection:
leaderElect: true
foo: bar`, configKubeconfig)), os.FileMode(0600)); err != nil {
t.Fatal(err)
}
duplicateFieldConfigLenient := filepath.Join(tmpDir, "scheduler_invalid_duplicate_fields_lenient.yaml")
if err := ioutil.WriteFile(duplicateFieldConfigLenient, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
leaderElection:
leaderElect: true
leaderElect: false`, configKubeconfig)), os.FileMode(0600)); err != nil {
t.Fatal(err)
}
duplicateFieldConfig := filepath.Join(tmpDir, "scheduler_invalid_duplicate_fields.yaml")
if err := ioutil.WriteFile(duplicateFieldConfig, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha1
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
@ -176,7 +209,7 @@ users:
// plugin config
pluginconfigFile := filepath.Join(tmpDir, "plugin.yaml")
if err := ioutil.WriteFile(pluginconfigFile, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha1
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
@ -293,7 +326,7 @@ pluginConfig:
{
name: "config file in componentconfig/v1alpha1",
options: &Options{
ConfigFile: oldconfigFile,
ConfigFile: oldConfigFile,
ComponentConfig: func() kubeschedulerconfig.KubeSchedulerConfiguration {
cfg, err := newDefaultComponentConfig()
if err != nil {
@ -306,9 +339,14 @@ pluginConfig:
},
{
name: "invalid config file in componentconfig/v1alpha2",
options: &Options{ConfigFile: invalidconfigFile},
expectedError: "no kind \"KubeSchedulerConfiguration\" is registered for version \"componentconfig/v1alpha2\"",
name: "unknown version kubescheduler.config.k8s.io/unknown",
options: &Options{ConfigFile: unknownVersionConfig},
expectedError: "no kind \"KubeSchedulerConfiguration\" is registered for version \"kubescheduler.config.k8s.io/unknown\"",
},
{
name: "config file with no version",
options: &Options{ConfigFile: noVersionConfig},
expectedError: "Object 'apiVersion' is missing",
},
{
name: "kubeconfig flag",
@ -522,9 +560,9 @@ pluginConfig:
expectedError: "no configuration has been provided",
},
{
name: "unknown field",
name: "unknown field lenient (v1alpha1)",
options: &Options{
ConfigFile: unknownFieldConfig,
ConfigFile: unknownFieldConfigLenient,
},
// TODO (obitech): Remove this comment and add a new test for v1alpha2, when it's available, as this should fail then.
// expectedError: "found unknown field: foo",
@ -565,9 +603,17 @@ pluginConfig:
},
},
{
name: "duplicate fields",
name: "unknown field",
options: &Options{
ConfigFile: duplicateFieldConfig,
ConfigFile: unknownFieldConfig,
},
expectedError: "found unknown field: foo",
checkErrFn: runtime.IsStrictDecodingError,
},
{
name: "duplicate fields lenient (v1alpha1)",
options: &Options{
ConfigFile: duplicateFieldConfigLenient,
},
// TODO (obitech): Remove this comment and add a new test for v1alpha2, when it's available, as this should fail then.
// expectedError: `key "leaderElect" already set`,
@ -607,6 +653,14 @@ pluginConfig:
Plugins: nil,
},
},
{
name: "duplicate fields",
options: &Options{
ConfigFile: duplicateFieldConfig,
},
expectedError: `key "leaderElect" already set`,
checkErrFn: runtime.IsStrictDecodingError,
},
}
for _, tc := range testcases {
@ -618,7 +672,7 @@ pluginConfig:
if err != nil {
if tc.expectedError != "" || tc.checkErrFn != nil {
if tc.expectedError != "" {
assert.Contains(t, err.Error(), tc.expectedError, tc.name)
assert.Contains(t, err.Error(), tc.expectedError)
}
if tc.checkErrFn != nil {
assert.True(t, tc.checkErrFn(err), "got error: %v", err)
@ -629,8 +683,8 @@ pluginConfig:
return
}
if !reflect.DeepEqual(config.ComponentConfig, tc.expectedConfig) {
t.Errorf("config.diff:\n%s", diff.ObjectReflectDiff(tc.expectedConfig, config.ComponentConfig))
if diff := cmp.Diff(tc.expectedConfig, config.ComponentConfig); diff != "" {
t.Errorf("incorrect config (-want, +got):\n%s", diff)
}
// ensure we have a client

View File

@ -40,9 +40,9 @@ func init() {
// AddToScheme builds the kubescheduler scheme using all known versions of the kubescheduler api.
func AddToScheme(scheme *runtime.Scheme) {
utilruntime.Must(kubeschedulerconfig.AddToScheme(Scheme))
utilruntime.Must(kubeschedulerconfigv1.AddToScheme(Scheme))
utilruntime.Must(kubeschedulerconfigv1alpha1.AddToScheme(Scheme))
utilruntime.Must(kubeschedulerconfigv1alpha2.AddToScheme(Scheme))
utilruntime.Must(scheme.SetVersionPriority(kubeschedulerconfigv1alpha1.SchemeGroupVersion))
utilruntime.Must(kubeschedulerconfig.AddToScheme(scheme))
utilruntime.Must(kubeschedulerconfigv1.AddToScheme(scheme))
utilruntime.Must(kubeschedulerconfigv1alpha1.AddToScheme(scheme))
utilruntime.Must(kubeschedulerconfigv1alpha2.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(kubeschedulerconfigv1alpha2.SchemeGroupVersion, kubeschedulerconfigv1alpha1.SchemeGroupVersion))
}