kubeadm: handle strict config unmarshaling

pull/58/head
Lubomir I. Ivanov 2018-11-10 04:27:15 +02:00
parent 7b4d4bc8ac
commit cc60625930
21 changed files with 291 additions and 8 deletions

View File

@ -247,7 +247,6 @@ func TestMigrate(t *testing.T) {
# This is intentionally testing an old API version and the old kind naming and making sure the output is correct
apiVersion: kubeadm.k8s.io/v1alpha3
kind: InitConfiguration
kubernetesVersion: v1.12.0
`))
configFile, cleanup := tempConfig(t, cfg)
defer cleanup()

View File

@ -56,9 +56,12 @@ kind: InitConfiguration
nodeRegistration:
name: foo
criSocket: ""
apiEndpoint:
advertiseAddress: 1.2.3.4
localAPIEndpoint:
advertiseAddress: 192.168.2.2
bindPort: 6443
bootstrapTokens:
- token: ce3aa5.5ec8455bb76b379f
ttl: 24h
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
@ -67,21 +70,16 @@ apiServer:
certSANs: null
extraArgs: null
certificatesDir: %s
controllerManagerExtraArgs: null
etcd:
local:
dataDir: %s
image: ""
featureFlags: null
imageRepository: k8s.gcr.io
kubernetesVersion: %s
networking:
dnsDomain: cluster.local
podSubnet: ""
serviceSubnet: 10.96.0.0/12
schedulerExtraArgs: null
token: ce3aa5.5ec8455bb76b379f
tokenTTL: 24h
useHyperKubeImage: false
`
)

View File

@ -39,6 +39,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
nodeutil "k8s.io/kubernetes/pkg/util/node"
)
@ -211,6 +212,9 @@ func BytesToInternalConfig(b []byte) (*kubeadmapi.InitConfiguration, error) {
}
for gvk, fileContent := range gvkmap {
// verify the validity of the YAML
strict.VerifyUnmarshalStrict(fileContent, gvk)
// Try to get the registration for the ComponentConfig based on the kind
regKind := componentconfigs.RegistrationKind(gvk.Kind)
registration, found := componentconfigs.Known[regKind]

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
)
// SetJoinDynamicDefaults checks and sets configuration values for the JoinConfiguration object
@ -88,6 +89,8 @@ func JoinConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedc
for gvk, bytes := range gvkmap {
if gvk.Kind == constants.JoinConfigurationKind {
joinBytes = bytes
// verify the validity of the YAML
strict.VerifyUnmarshalStrict(bytes, gvk)
}
}

View File

@ -0,0 +1,58 @@
/*
Copyright 2018 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 strict
import (
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
"sigs.k8s.io/yaml"
)
// VerifyUnmarshalStrict takes a YAML byte slice and a GroupVersionKind and verifies if the YAML
// schema is known and if it unmarshals with strict mode.
//
// TODO(neolit123): The returned error here is currently ignored everywhere and a klog warning is thrown instead.
// We don't want to turn this into an actual error yet. Eventually this can be controlled with an optional CLI flag.
func VerifyUnmarshalStrict(bytes []byte, gvk schema.GroupVersionKind) error {
var (
iface interface{}
err error
)
iface, err = scheme.Scheme.New(gvk)
if err != nil {
iface, err = componentconfigs.Scheme.New(gvk)
if err != nil {
err := errors.Errorf("unknown configuration %#v for scheme definitions in %q and %q",
gvk, scheme.Scheme.Name(), componentconfigs.Scheme.Name())
klog.Warning(err.Error())
return err
}
}
if err := yaml.UnmarshalStrict(bytes, iface); err != nil {
err := errors.Wrapf(err, "error unmarshaling configuration %#v", gvk)
klog.Warning(err.Error())
return err
}
return nil
}

View File

@ -0,0 +1,168 @@
/*
Copyright 2018 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 strict
import (
"io/ioutil"
"path/filepath"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
kubeproxyconfigv1alpha1 "k8s.io/kube-proxy/config/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
func TestVerifyUnmarshalStrict(t *testing.T) {
const (
pathTestData = "testdata/"
)
var testFiles = []struct {
fileName string
kind string
groupVersion schema.GroupVersion
expectedError bool
}{
// tests with file errors
{
fileName: "invalid_duplicate_field_clustercfg.yaml",
kind: constants.InitConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_duplicate_field_initcfg.yaml",
kind: constants.InitConfigurationKind,
groupVersion: kubeadmapiv1alpha3.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_duplicate_field_joincfg.yaml",
kind: constants.JoinConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_duplicate_field_kubeletcfg.yaml",
kind: string(componentconfigs.KubeletConfigurationKind),
groupVersion: kubeletconfigv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_duplicate_field_kubeproxycfg.yaml",
kind: string(componentconfigs.KubeProxyConfigurationKind),
groupVersion: kubeproxyconfigv1alpha1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_unknown_field_clustercfg.yaml",
kind: constants.ClusterConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_unknown_field_initcfg.yaml",
kind: constants.InitConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_unknown_field_joincfg.yaml",
kind: constants.JoinConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_unknown_field_kubeletcfg.yaml",
kind: string(componentconfigs.KubeletConfigurationKind),
groupVersion: kubeletconfigv1beta1.SchemeGroupVersion,
expectedError: true,
},
{
fileName: "invalid_unknown_field_kubeproxycfg.yaml",
kind: string(componentconfigs.KubeProxyConfigurationKind),
groupVersion: kubeproxyconfigv1alpha1.SchemeGroupVersion,
expectedError: true,
},
// test unknown groupVersion and kind
{
fileName: "valid_clustercfg.yaml",
kind: constants.ClusterConfigurationKind,
groupVersion: schema.GroupVersion{Group: "someGroup", Version: "v1"},
expectedError: true,
},
{
fileName: "valid_clustercfg.yaml",
kind: "SomeUnknownKind",
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: true,
},
// valid tests
{
fileName: "valid_clustercfg.yaml",
kind: constants.ClusterConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: false,
},
{
fileName: "valid_initcfg.yaml",
kind: constants.InitConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: false,
},
{
fileName: "valid_joincfg.yaml",
kind: constants.JoinConfigurationKind,
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
expectedError: false,
},
{
fileName: "valid_kubeletcfg.yaml",
kind: string(componentconfigs.KubeletConfigurationKind),
groupVersion: kubeletconfigv1beta1.SchemeGroupVersion,
expectedError: false,
},
{
fileName: "valid_kubeproxycfg.yaml",
kind: string(componentconfigs.KubeProxyConfigurationKind),
groupVersion: kubeproxyconfigv1alpha1.SchemeGroupVersion,
expectedError: false,
},
}
for _, test := range testFiles {
t.Run(test.fileName, func(t *testing.T) {
bytes, err := ioutil.ReadFile(filepath.Join(pathTestData, test.fileName))
if err != nil {
t.Fatalf("couldn't read test data: %v", err)
}
gvk := schema.GroupVersionKind{
Group: test.groupVersion.Group,
Version: test.groupVersion.Version,
Kind: test.kind,
}
err = VerifyUnmarshalStrict(bytes, gvk)
if (err != nil) != test.expectedError {
t.Errorf("expected error %v, got %v, error: %v", err != nil, test.expectedError, err)
}
})
}
}

View File

@ -0,0 +1,4 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
controlPlaneEndpoint: test1
controlPlaneEndpoint: test2

View File

@ -0,0 +1,6 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
bootstrapTokens:
- token: "9a08jv.c0izixklcxtmnze7"
bootstrapTokens:
- token: "9a08jv.c0izixklcxtmnze7"

View File

@ -0,0 +1,4 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: JoinConfiguration
caCertPath: relativepath
caCertPath: relativepath

View File

@ -0,0 +1,4 @@
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: 1.2.3.4
address: 1.2.3.4

View File

@ -0,0 +1,4 @@
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
portRange: ""
portRange: ""

View File

@ -0,0 +1,3 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
unknownField: test

View File

@ -0,0 +1,3 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
unknownField: test

View File

@ -0,0 +1,3 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: JoinConfiguration
unknownField: test

View File

@ -0,0 +1,3 @@
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
unknownField: unknown

View File

@ -0,0 +1,3 @@
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
unknownField: unknown

View File

@ -0,0 +1,3 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
controlPlaneEndpoint: 202.0.100.1

View File

@ -0,0 +1,4 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
bootstrapTokens:
- token: "9a08jv.c0izixklcxtmnze7"

View File

@ -0,0 +1,3 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: JoinConfiguration
caCertPath: relativepath

View File

@ -0,0 +1,3 @@
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: 1.2.3.4

View File

@ -0,0 +1,3 @@
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
portRange: ""