From 930ca6ceb2f2ded1b658d312db75ee2a87863a69 Mon Sep 17 00:00:00 2001 From: "Rostislav M. Georgiev" Date: Wed, 17 Jun 2020 14:06:40 +0300 Subject: [PATCH 1/2] kubeadm: Refactor component config tests Over the course of recent development of the `componentconfigs` package, it became evident that most of the tests in this package cannot be implemented without using a component config. As all of the currently supported component configs are external to the kubeadm project (kubelet and kube-proxy), practically all of the tests in this package are now dependent on external code. This is not desirable, because other component's configs may change frequently and without much of a notice. In particular many configs add new fields without bumping their versions. In addition to that, some components may be deprecated in the future and many tests may use their configs as a place holder of a component config just to test some common functionality. To top that, there are many tests that test the same common functionality several times (for each different component config). Thus a kubeadm managed replacement and a fake test environment are introduced. The new test environment uses kubeadm's very own `ClusterConfiguration`. ClusterConfiguration is normally not managed by the `componentconfigs` package. It's only used, because of the following: - It's a versioned API that is under the control of kubeadm maintainers. This enables us to test the componentconfigs package more thoroughly without having to have full and always up to date knowledge about the config of another component. - Other components often introduce new fields in their configs without bumping up the config version. This, often times, requires that the PR that introduces such new fields to touch kubeadm test code. Doing so, requires more work on the part of developers and reviewers. When kubeadm moves out of k/k this would allow for more sporadic breaks in kubeadm tests as PRs that merge in k/k and introduce new fields won't be able to fix the tests in kubeadm. - If we implement tests for all common functionality using the config of another component and it gets deprecated and/or we stop supporting it in production, we'll have to focus on a massive test refactoring or just continue importing this config just for test use. Thus, to reduce maintenance costs without sacrificing test coverage, we introduce this mini-framework and set of tests here which replace the normal component configs with a single one (`ClusterConfiguration`) and test the component config independent logic of this package. As a result of this, many of the older test cases are refactored and greatly simplified to reflect on the new change as well. The old tests that are strictly tied to specific component configs (like the defaulting tests) are left unchanged. Signed-off-by: Rostislav M. Georgiev --- cmd/kubeadm/app/componentconfigs/BUILD | 5 +- .../app/componentconfigs/configset_test.go | 593 +------------- .../app/componentconfigs/fakeconfig_test.go | 722 ++++++++++++++++++ .../app/componentconfigs/kubelet_test.go | 378 +-------- .../app/componentconfigs/kubeproxy_test.go | 401 +--------- 5 files changed, 813 insertions(+), 1286 deletions(-) create mode 100644 cmd/kubeadm/app/componentconfigs/fakeconfig_test.go diff --git a/cmd/kubeadm/app/componentconfigs/BUILD b/cmd/kubeadm/app/componentconfigs/BUILD index 2a0b648e8aa..2f456d8b9a0 100644 --- a/cmd/kubeadm/app/componentconfigs/BUILD +++ b/cmd/kubeadm/app/componentconfigs/BUILD @@ -45,12 +45,14 @@ go_test( srcs = [ "checksums_test.go", "configset_test.go", + "fakeconfig_test.go", "kubelet_test.go", "kubeproxy_test.go", ], embed = [":go_default_library"], deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1beta2:go_default_library", "//cmd/kubeadm/app/apis/output:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", @@ -59,7 +61,8 @@ go_test( "//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", - "//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/component-base/config/v1alpha1:go_default_library", "//staging/src/k8s.io/kube-proxy/config/v1alpha1:go_default_library", diff --git a/cmd/kubeadm/app/componentconfigs/configset_test.go b/cmd/kubeadm/app/componentconfigs/configset_test.go index 13652d3ee87..7189e9f7263 100644 --- a/cmd/kubeadm/app/componentconfigs/configset_test.go +++ b/cmd/kubeadm/app/componentconfigs/configset_test.go @@ -17,25 +17,26 @@ limitations under the License. package componentconfigs import ( - "reflect" "testing" "github.com/lithammer/dedent" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/version" clientsetfake "k8s.io/client-go/kubernetes/fake" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - outputapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/output" "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" ) +func testClusterCfg() *kubeadmapi.ClusterConfiguration { + return &kubeadmapi.ClusterConfiguration{ + KubernetesVersion: constants.CurrentKubernetesVersion.String(), + } +} + func TestDefault(t *testing.T) { - clusterCfg := &kubeadmapi.ClusterConfiguration{} + clusterCfg := testClusterCfg() localAPIEndpoint := &kubeadmapi.APIEndpoint{} nodeRegOps := &kubeadmapi.NodeRegistrationOptions{} @@ -47,39 +48,18 @@ func TestDefault(t *testing.T) { } func TestFromCluster(t *testing.T) { - clusterCfg := &kubeadmapi.ClusterConfiguration{ - KubernetesVersion: constants.CurrentKubernetesVersion.String(), - } - - k8sVersion := version.MustParseGeneric(clusterCfg.KubernetesVersion) - objects := []runtime.Object{ - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - }, - }, - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(k8sVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, + testKubeProxyConfigMap(` + apiVersion: kubeproxy.config.k8s.io/v1alpha1 + kind: KubeProxyConfiguration + `), + testKubeletConfigMap(` + apiVersion: kubelet.config.k8s.io/v1beta1 + kind: KubeletConfiguration + `), } client := clientsetfake.NewSimpleClientset(objects...) + clusterCfg := testClusterCfg() if err := FetchFromCluster(clusterCfg, client); err != nil { t.Fatalf("FetchFromCluster failed: %v", err) @@ -103,7 +83,7 @@ func TestFetchFromDocumentMap(t *testing.T) { t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) } - clusterCfg := &kubeadmapi.ClusterConfiguration{} + clusterCfg := testClusterCfg() if err = FetchFromDocumentMap(clusterCfg, gvkmap); err != nil { t.Fatalf("FetchFromDocumentMap failed: %v", err) } @@ -112,542 +92,3 @@ func TestFetchFromDocumentMap(t *testing.T) { t.Fatalf("missmatch between supplied and loaded type numbers:\n\tgot: %d\n\texpected: %d", len(clusterCfg.ComponentConfigs), len(gvkmap)) } } - -func kubeproxyConfigMap(contents string) *v1.ConfigMap { - return &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: dedent.Dedent(contents), - }, - } -} - -func TestFetchFromClusterWithLocalUpgrades(t *testing.T) { - cases := []struct { - desc string - obj runtime.Object - config string - expectedValue string - expectedErr bool - }{ - { - desc: "reconginzed cluster object without overwrite is used", - obj: kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - hostnameOverride: foo - `), - expectedValue: "foo", - }, - { - desc: "reconginzed cluster object with overwrite is not used", - obj: kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - hostnameOverride: foo - `), - config: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - hostnameOverride: bar - `), - expectedValue: "bar", - }, - { - desc: "old config without overwrite returns an error", - obj: kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - hostnameOverride: foo - `), - expectedErr: true, - }, - { - desc: "old config with recognized overwrite returns success", - obj: kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - hostnameOverride: foo - `), - config: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - hostnameOverride: bar - `), - expectedValue: "bar", - }, - { - desc: "old config with old overwrite returns an error", - obj: kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - hostnameOverride: foo - `), - config: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - hostnameOverride: bar - `), - expectedErr: true, - }, - } - for _, test := range cases { - t.Run(test.desc, func(t *testing.T) { - clusterCfg := &kubeadmapi.ClusterConfiguration{ - KubernetesVersion: constants.CurrentKubernetesVersion.String(), - } - - k8sVersion := version.MustParseGeneric(clusterCfg.KubernetesVersion) - - client := clientsetfake.NewSimpleClientset( - test.obj, - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(k8sVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - ) - - docmap, err := kubeadmutil.SplitYAMLDocuments([]byte(test.config)) - if err != nil { - t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) - } - - err = FetchFromClusterWithLocalOverwrites(clusterCfg, client, docmap) - if err != nil { - if !test.expectedErr { - t.Errorf("unexpected failure: %v", err) - } - } else { - if test.expectedErr { - t.Error("unexpected success") - } else { - kubeproxyCfg, ok := clusterCfg.ComponentConfigs[KubeProxyGroup] - if !ok { - t.Error("the config was reported as loaded, but was not in reality") - } else { - actualConfig, ok := kubeproxyCfg.(*kubeProxyConfig) - if !ok { - t.Error("the config is not of the expected type") - } else if actualConfig.config.HostnameOverride != test.expectedValue { - t.Errorf("unexpected value:\n\tgot: %q\n\texpected: %q", actualConfig.config.HostnameOverride, test.expectedValue) - } - } - } - } - }) - } -} - -func TestGetVersionStates(t *testing.T) { - tests := []struct { - desc string - objects []runtime.Object - substitutes string - expected []outputapi.ComponentConfigVersionState - }{ - { - desc: "Normal config", - objects: []runtime.Object{ - kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - }, - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: false, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1beta1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: false, - }, - }, - }, - { - desc: "Normal config ignoring a current substitute", - objects: []runtime.Object{ - kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - }, - substitutes: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: false, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1beta1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: false, - }, - }, - }, - { - desc: "Normal config with an old substitute", - objects: []runtime.Object{ - kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - }, - substitutes: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha0", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: true, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1beta1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: false, - }, - }, - }, - { - desc: "Old user supplied config", - objects: []runtime.Object{ - kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1alpha1 - kind: KubeletConfiguration - `), - }, - }, - }, - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha0", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: true, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: true, - }, - }, - }, - { - desc: "Old user supplied config with a proper substitute", - objects: []runtime.Object{ - kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1alpha1 - kind: KubeletConfiguration - `), - }, - }, - }, - substitutes: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: false, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: true, - }, - }, - }, - { - desc: "Old user supplied config with an old substitute", - objects: []runtime.Object{ - kubeproxyConfigMap(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1alpha1 - kind: KubeletConfiguration - `), - }, - }, - }, - substitutes: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha0", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: true, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: true, - }, - }, - }, - { - desc: "Old kubeadm generated config", - objects: []runtime.Object{ - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - Annotations: map[string]string{ - constants.ComponentConfigHashAnnotationKey: "sha256:8d3dfd7abcac205f6744d8e9db44505cce0c15b0a5395501e272fc18bd54c13c", - }, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - }, - }, - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - }, - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: false, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1beta1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: false, - }, - }, - }, - { - desc: "Old kubeadm generated config with a proper substitute", - objects: []runtime.Object{ - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - Annotations: map[string]string{ - constants.ComponentConfigHashAnnotationKey: "sha256:8d3dfd7abcac205f6744d8e9db44505cce0c15b0a5395501e272fc18bd54c13c", - }, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - }, - }, - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - }, - substitutes: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - `), - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha1", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: false, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1beta1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: false, - }, - }, - }, - { - desc: "Old kubeadm generated config with an old substitute", - objects: []runtime.Object{ - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - Annotations: map[string]string{ - constants.ComponentConfigHashAnnotationKey: "sha256:8d3dfd7abcac205f6744d8e9db44505cce0c15b0a5395501e272fc18bd54c13c", - }, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - }, - }, - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - `), - }, - }, - }, - substitutes: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - expected: []outputapi.ComponentConfigVersionState{ - { - Group: "kubeproxy.config.k8s.io", - CurrentVersion: "v1alpha0", - PreferredVersion: "v1alpha1", - ManualUpgradeRequired: true, - }, - { - Group: "kubelet.config.k8s.io", - CurrentVersion: "v1beta1", - PreferredVersion: "v1beta1", - ManualUpgradeRequired: false, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.desc, func(t *testing.T) { - docmap, err := kubeadmutil.SplitYAMLDocuments([]byte(test.substitutes)) - if err != nil { - t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) - } - - clusterCfg := &kubeadmapi.ClusterConfiguration{ - KubernetesVersion: constants.CurrentKubernetesVersion.String(), - } - client := clientsetfake.NewSimpleClientset(test.objects...) - got, err := GetVersionStates(clusterCfg, client, docmap) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !reflect.DeepEqual(got, test.expected) { - t.Fatalf("unexpected result:\n\texpected: %v\n\tgot: %v", test.expected, got) - } - }) - } -} diff --git a/cmd/kubeadm/app/componentconfigs/fakeconfig_test.go b/cmd/kubeadm/app/componentconfigs/fakeconfig_test.go new file mode 100644 index 00000000000..4db2625f3ec --- /dev/null +++ b/cmd/kubeadm/app/componentconfigs/fakeconfig_test.go @@ -0,0 +1,722 @@ +/* +Copyright 2020 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 componentconfigs + +import ( + "crypto/sha256" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/lithammer/dedent" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clientset "k8s.io/client-go/kubernetes" + clientsetfake "k8s.io/client-go/kubernetes/fake" + kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" + kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" + outputapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/output" + "k8s.io/kubernetes/cmd/kubeadm/app/constants" + kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" +) + +// All tests in this file use an alternative set of `known` component configs. +// In this case it's just one known config and it's kubeadm's very own ClusterConfiguration. +// ClusterConfiguration is normally not managed by this package. It's only used, because of the following: +// - It's a versioned API that is under the control of kubeadm maintainers. This enables us to test +// the componentconfigs package more thoroughly without having to have full and always up to date +// knowledge about the config of another component. +// - Other components often introduce new fields in their configs without bumping up the config version. +// This, often times, requires that the PR that introduces such new fields to touch kubeadm test code. +// Doing so, requires more work on the part of developers and reviewers. When kubeadm moves out of k/k +// this would allow for more sporadic breaks in kubeadm tests as PRs that merge in k/k and introduce +// new fields won't be able to fix the tests in kubeadm. +// - If we implement tests for all common functionality using the config of another component and it gets +// deprecated and/or we stop supporting it in production, we'll have to focus on a massive test refactoring +// or just continue importing this config just for test use. +// +// Thus, to reduce maintenance costs without sacrificing test coverage, we introduce this mini-framework +// and set of tests here which replace the normal component configs with a single one (ClusterConfiguration) +// and test the component config independent logic of this package. + +// clusterConfigHandler is the handler instance for the latest supported ClusterConfiguration to be used in tests +var clusterConfigHandler = handler{ + GroupVersion: kubeadmapiv1.SchemeGroupVersion, + AddToScheme: kubeadmapiv1.AddToScheme, + CreateEmpty: func() kubeadmapi.ComponentConfig { + return &clusterConfig{ + configBase: configBase{ + GroupVersion: kubeadmapiv1.SchemeGroupVersion, + }, + } + }, + fromCluster: clusterConfigFromCluster, +} + +func clusterConfigFromCluster(h *handler, clientset clientset.Interface, _ *kubeadmapi.ClusterConfiguration) (kubeadmapi.ComponentConfig, error) { + return h.fromConfigMap(clientset, constants.KubeadmConfigConfigMap, constants.ClusterConfigurationConfigMapKey, true) +} + +type clusterConfig struct { + configBase + config kubeadmapiv1.ClusterConfiguration +} + +func (cc *clusterConfig) DeepCopy() kubeadmapi.ComponentConfig { + result := &clusterConfig{} + cc.configBase.DeepCopyInto(&result.configBase) + cc.config.DeepCopyInto(&result.config) + return result +} + +func (cc *clusterConfig) Marshal() ([]byte, error) { + return cc.configBase.Marshal(&cc.config) +} + +func (cc *clusterConfig) Unmarshal(docmap kubeadmapi.DocumentMap) error { + return cc.configBase.Unmarshal(docmap, &cc.config) +} + +func (cc *clusterConfig) Default(_ *kubeadmapi.ClusterConfiguration, _ *kubeadmapi.APIEndpoint, _ *kubeadmapi.NodeRegistrationOptions) { + cc.config.ClusterName = "foo" + cc.config.KubernetesVersion = "bar" +} + +// fakeKnown replaces temporarily during the execution of each test here known (in configset.go) +var fakeKnown = []*handler{ + &clusterConfigHandler, +} + +// fakeKnownContext is the func that houses the fake component config context. +// NOTE: It does not support concurrent test execution! +func fakeKnownContext(f func()) { + // Save the real values + realKnown := known + realScheme := Scheme + realCodecs := Codecs + + // Replace the context with the fake context + known = fakeKnown + Scheme = kubeadmscheme.Scheme + Codecs = kubeadmscheme.Codecs + + // Upon function exit, restore the real values + defer func() { + known = realKnown + Scheme = realScheme + Codecs = realCodecs + }() + + // Call f in the fake context + f() +} + +// testClusterConfigMap is a short hand for creating and possibly signing a test config map. +// This produces config maps that can be loaded by clusterConfigFromCluster +func testClusterConfigMap(yaml string, signIt bool) *v1.ConfigMap { + cm := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.KubeadmConfigConfigMap, + Namespace: metav1.NamespaceSystem, + }, + Data: map[string]string{ + constants.ClusterConfigurationConfigMapKey: dedent.Dedent(yaml), + }, + } + + if signIt { + SignConfigMap(cm) + } + + return cm +} + +// oldClusterConfigVersion is used as an old unsupported version in tests throughout this file +const oldClusterConfigVersion = "v1alpha1" + +var ( + // currentClusterConfigVersion represents the current actively supported version of ClusterConfiguration + currentClusterConfigVersion = kubeadmapiv1.SchemeGroupVersion.Version + + // currentFooClusterConfig is a minimal currently supported ClusterConfiguration + // with a well known value of clusterName (in this case `foo`) + currentFooClusterConfig = fmt.Sprintf(` + apiVersion: %s + kind: ClusterConfiguration + clusterName: foo + `, kubeadmapiv1.SchemeGroupVersion) + + // oldFooClusterConfig is a minimal unsupported ClusterConfiguration + // with a well known value of clusterName (in this case `foo`) + oldFooClusterConfig = fmt.Sprintf(` + apiVersion: %s/%s + kind: ClusterConfiguration + clusterName: foo + `, kubeadmapiv1.GroupName, oldClusterConfigVersion) + + // currentBarClusterConfig is a minimal currently supported ClusterConfiguration + // with a well known value of clusterName (in this case `bar`) + currentBarClusterConfig = fmt.Sprintf(` + apiVersion: %s + kind: ClusterConfiguration + clusterName: bar + `, kubeadmapiv1.SchemeGroupVersion) + + // oldBarClusterConfig is a minimal unsupported ClusterConfiguration + // with a well known value of clusterName (in this case `bar`) + oldBarClusterConfig = fmt.Sprintf(` + apiVersion: %s/%s + kind: ClusterConfiguration + clusterName: bar + `, kubeadmapiv1.GroupName, oldClusterConfigVersion) + + // This is the "minimal" valid config that can be unmarshalled to and from YAML. + // Due to same static defaulting it's not exactly small in size. + validUnmarshallableClusterConfig = struct { + yaml string + obj kubeadmapiv1.ClusterConfiguration + }{ + yaml: dedent.Dedent(` + apiServer: + timeoutForControlPlane: 4m + apiVersion: kubeadm.k8s.io/v1beta2 + certificatesDir: /etc/kubernetes/pki + clusterName: LeCluster + controllerManager: {} + dns: + type: CoreDNS + etcd: + local: + dataDir: /var/lib/etcd + imageRepository: k8s.gcr.io + kind: ClusterConfiguration + kubernetesVersion: 1.2.3 + networking: + dnsDomain: cluster.local + serviceSubnet: 10.96.0.0/12 + scheduler: {} + `), + obj: kubeadmapiv1.ClusterConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kubeadmapiv1.SchemeGroupVersion.String(), + Kind: "ClusterConfiguration", + }, + ClusterName: "LeCluster", + KubernetesVersion: "1.2.3", + CertificatesDir: "/etc/kubernetes/pki", + ImageRepository: "k8s.gcr.io", + Networking: kubeadmapiv1.Networking{ + DNSDomain: "cluster.local", + ServiceSubnet: "10.96.0.0/12", + }, + DNS: kubeadmapiv1.DNS{ + Type: kubeadmapiv1.CoreDNS, + }, + Etcd: kubeadmapiv1.Etcd{ + Local: &kubeadmapiv1.LocalEtcd{ + DataDir: "/var/lib/etcd", + }, + }, + APIServer: kubeadmapiv1.APIServer{ + TimeoutForControlPlane: &metav1.Duration{ + Duration: 4 * time.Minute, + }, + }, + }, + } +) + +func TestConfigBaseMarshal(t *testing.T) { + fakeKnownContext(func() { + cfg := &clusterConfig{ + configBase: configBase{ + GroupVersion: kubeadmapiv1.SchemeGroupVersion, + }, + config: kubeadmapiv1.ClusterConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kubeadmapiv1.SchemeGroupVersion.String(), + Kind: "ClusterConfiguration", + }, + ClusterName: "LeCluster", + KubernetesVersion: "1.2.3", + }, + } + + b, err := cfg.Marshal() + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + got := strings.TrimSpace(string(b)) + expected := strings.TrimSpace(dedent.Dedent(` + apiServer: {} + apiVersion: kubeadm.k8s.io/v1beta2 + clusterName: LeCluster + controllerManager: {} + dns: + type: "" + etcd: {} + kind: ClusterConfiguration + kubernetesVersion: 1.2.3 + networking: {} + scheduler: {} + `)) + + if expected != got { + t.Fatalf("Missmatch between expected and got:\nExpected:\n%s\n---\nGot:\n%s", expected, got) + } + }) +} + +func TestConfigBaseUnmarshal(t *testing.T) { + fakeKnownContext(func() { + expected := &clusterConfig{ + configBase: configBase{ + GroupVersion: kubeadmapiv1.SchemeGroupVersion, + }, + config: validUnmarshallableClusterConfig.obj, + } + + gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(validUnmarshallableClusterConfig.yaml)) + if err != nil { + t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) + } + + got := &clusterConfig{ + configBase: configBase{ + GroupVersion: kubeadmapiv1.SchemeGroupVersion, + }, + } + if err = got.Unmarshal(gvkmap); err != nil { + t.Fatalf("unexpected failure of Unmarshal: %v", err) + } + + if !reflect.DeepEqual(got, expected) { + t.Fatalf("Missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", expected, got) + } + }) +} + +func TestGeneratedConfigFromCluster(t *testing.T) { + fakeKnownContext(func() { + testYAML := dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1beta2 + kind: ClusterConfiguration + `) + testYAMLHash := fmt.Sprintf("sha256:%x", sha256.Sum256([]byte(testYAML))) + // The SHA256 sum of "The quick brown fox jumps over the lazy dog" + const mismatchHash = "sha256:d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" + tests := []struct { + name string + hash string + userSupplied bool + }{ + { + name: "Matching hash means generated config", + hash: testYAMLHash, + }, + { + name: "Missmatching hash means user supplied config", + hash: mismatchHash, + userSupplied: true, + }, + { + name: "No hash means user supplied config", + userSupplied: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + configMap := testClusterConfigMap(testYAML, false) + if test.hash != "" { + configMap.Annotations = map[string]string{ + constants.ComponentConfigHashAnnotationKey: test.hash, + } + } + + client := clientsetfake.NewSimpleClientset(configMap) + cfg, err := clusterConfigHandler.FromCluster(client, testClusterCfg()) + if err != nil { + t.Fatalf("unexpected failure of FromCluster: %v", err) + } + + got := cfg.IsUserSupplied() + if got != test.userSupplied { + t.Fatalf("mismatch between expected and got:\n\tExpected: %t\n\tGot: %t", test.userSupplied, got) + } + }) + } + }) +} + +// runClusterConfigFromTest holds common test case data and evaluation code for handler.From* functions +func runClusterConfigFromTest(t *testing.T, perform func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error)) { + fakeKnownContext(func() { + tests := []struct { + name string + in string + out *clusterConfig + expectErr bool + }{ + { + name: "Empty document map should return nothing successfully", + }, + { + name: "Non-empty document map without the proper API group returns nothing successfully", + in: dedent.Dedent(` + apiVersion: api.example.com/v1 + kind: Configuration + `), + }, + { + name: "Old config version returns an error", + in: dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1alpha1 + kind: ClusterConfiguration + `), + expectErr: true, + }, + { + name: "Unknown kind returns an error", + in: dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1beta2 + kind: Configuration + `), + expectErr: true, + }, + { + name: "Valid config gets loaded", + in: validUnmarshallableClusterConfig.yaml, + out: &clusterConfig{ + configBase: configBase{ + GroupVersion: clusterConfigHandler.GroupVersion, + userSupplied: true, + }, + config: validUnmarshallableClusterConfig.obj, + }, + }, + { + name: "Valid config gets loaded even if coupled with an extra document", + in: "apiVersion: api.example.com/v1\nkind: Configuration\n---\n" + validUnmarshallableClusterConfig.yaml, + out: &clusterConfig{ + configBase: configBase{ + GroupVersion: clusterConfigHandler.GroupVersion, + userSupplied: true, + }, + config: validUnmarshallableClusterConfig.obj, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + componentCfg, err := perform(t, test.in) + if err != nil { + if !test.expectErr { + t.Errorf("unexpected failure: %v", err) + } + } else { + if test.expectErr { + t.Error("unexpected success") + } else { + if componentCfg == nil { + if test.out != nil { + t.Error("unexpected nil result") + } + } else { + if got, ok := componentCfg.(*clusterConfig); !ok { + t.Error("different result type") + } else { + if test.out == nil { + t.Errorf("unexpected result: %v", got) + } else { + if !reflect.DeepEqual(test.out, got) { + t.Errorf("missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", test.out, got) + } + } + } + } + } + } + }) + } + }) +} + +func TestLoadingFromDocumentMap(t *testing.T) { + runClusterConfigFromTest(t, func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error) { + gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(in)) + if err != nil { + t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) + } + + return clusterConfigHandler.FromDocumentMap(gvkmap) + }) +} + +func TestLoadingFromCluster(t *testing.T) { + runClusterConfigFromTest(t, func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error) { + client := clientsetfake.NewSimpleClientset( + testClusterConfigMap(in, false), + ) + + return clusterConfigHandler.FromCluster(client, testClusterCfg()) + }) +} + +func TestFetchFromClusterWithLocalOverwrites(t *testing.T) { + fakeKnownContext(func() { + cases := []struct { + desc string + obj runtime.Object + config string + expectedValue string + isNotLoaded bool + expectedErr bool + }{ + { + desc: "appropriate cluster object without overwrite is used", + obj: testClusterConfigMap(currentFooClusterConfig, false), + expectedValue: "foo", + }, + { + desc: "appropriate cluster object with appropriate overwrite is overwritten", + obj: testClusterConfigMap(currentFooClusterConfig, false), + config: dedent.Dedent(currentBarClusterConfig), + expectedValue: "bar", + }, + { + desc: "appropriate cluster object with old overwrite returns an error", + obj: testClusterConfigMap(currentFooClusterConfig, false), + config: dedent.Dedent(oldBarClusterConfig), + expectedErr: true, + }, + { + desc: "old config without overwrite returns an error", + obj: testClusterConfigMap(oldFooClusterConfig, false), + expectedErr: true, + }, + { + desc: "old config with appropriate overwrite returns the substitute", + obj: testClusterConfigMap(oldFooClusterConfig, false), + config: dedent.Dedent(currentBarClusterConfig), + expectedValue: "bar", + }, + { + desc: "old config with old overwrite returns an error", + obj: testClusterConfigMap(oldFooClusterConfig, false), + config: dedent.Dedent(oldBarClusterConfig), + expectedErr: true, + }, + { + desc: "appropriate signed cluster object without overwrite is used", + obj: testClusterConfigMap(currentFooClusterConfig, true), + expectedValue: "foo", + }, + { + desc: "appropriate signed cluster object with appropriate overwrite is overwritten", + obj: testClusterConfigMap(currentFooClusterConfig, true), + config: dedent.Dedent(currentBarClusterConfig), + expectedValue: "bar", + }, + { + desc: "appropriate signed cluster object with old overwrite returns an error", + obj: testClusterConfigMap(currentFooClusterConfig, true), + config: dedent.Dedent(oldBarClusterConfig), + expectedErr: true, + }, + { + desc: "old signed config without an overwrite is not loaded", + obj: testClusterConfigMap(oldFooClusterConfig, true), + isNotLoaded: true, + }, + { + desc: "old signed config with appropriate overwrite returns the substitute", + obj: testClusterConfigMap(oldFooClusterConfig, true), + config: dedent.Dedent(currentBarClusterConfig), + expectedValue: "bar", + }, + { + desc: "old signed config with old overwrite returns an error", + obj: testClusterConfigMap(oldFooClusterConfig, true), + config: dedent.Dedent(oldBarClusterConfig), + expectedErr: true, + }, + } + + for _, test := range cases { + t.Run(test.desc, func(t *testing.T) { + client := clientsetfake.NewSimpleClientset(test.obj) + + docmap, err := kubeadmutil.SplitYAMLDocuments([]byte(test.config)) + if err != nil { + t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) + } + + clusterCfg := testClusterCfg() + + err = FetchFromClusterWithLocalOverwrites(clusterCfg, client, docmap) + if err != nil { + if !test.expectedErr { + t.Errorf("unexpected failure: %v", err) + } + } else { + if test.expectedErr { + t.Error("unexpected success") + } else { + clusterCfg, ok := clusterCfg.ComponentConfigs[kubeadmapiv1.GroupName] + if !ok { + if !test.isNotLoaded { + t.Error("no config was loaded when it should have been") + } + } else { + actualConfig, ok := clusterCfg.(*clusterConfig) + if !ok { + t.Error("the config is not of the expected type") + } else if actualConfig.config.ClusterName != test.expectedValue { + t.Errorf("unexpected value:\n\tgot: %q\n\texpected: %q", actualConfig.config.ClusterName, test.expectedValue) + } + } + } + } + }) + } + }) +} + +func TestGetVersionStates(t *testing.T) { + fakeKnownContext(func() { + versionStateCurrent := outputapi.ComponentConfigVersionState{ + Group: kubeadmapiv1.GroupName, + CurrentVersion: currentClusterConfigVersion, + PreferredVersion: currentClusterConfigVersion, + } + versionStateOld := outputapi.ComponentConfigVersionState{ + Group: kubeadmapiv1.GroupName, + CurrentVersion: oldClusterConfigVersion, + PreferredVersion: currentClusterConfigVersion, + ManualUpgradeRequired: true, + } + + cases := []struct { + desc string + obj runtime.Object + config string + expected outputapi.ComponentConfigVersionState + }{ + { + desc: "appropriate cluster object without overwrite", + obj: testClusterConfigMap(currentFooClusterConfig, false), + expected: versionStateCurrent, + }, + { + desc: "appropriate cluster object with appropriate overwrite", + obj: testClusterConfigMap(currentFooClusterConfig, false), + config: dedent.Dedent(currentBarClusterConfig), + expected: versionStateCurrent, + }, + { + desc: "appropriate cluster object with old overwrite", + obj: testClusterConfigMap(currentFooClusterConfig, false), + config: dedent.Dedent(oldBarClusterConfig), + expected: versionStateOld, + }, + { + desc: "old config without overwrite returns an error", + obj: testClusterConfigMap(oldFooClusterConfig, false), + expected: versionStateOld, + }, + { + desc: "old config with appropriate overwrite", + obj: testClusterConfigMap(oldFooClusterConfig, false), + config: dedent.Dedent(currentBarClusterConfig), + expected: versionStateCurrent, + }, + { + desc: "old config with old overwrite", + obj: testClusterConfigMap(oldFooClusterConfig, false), + config: dedent.Dedent(oldBarClusterConfig), + expected: versionStateOld, + }, + { + desc: "appropriate signed cluster object without overwrite", + obj: testClusterConfigMap(currentFooClusterConfig, true), + expected: versionStateCurrent, + }, + { + desc: "appropriate signed cluster object with appropriate overwrite", + obj: testClusterConfigMap(currentFooClusterConfig, true), + config: dedent.Dedent(currentBarClusterConfig), + expected: versionStateCurrent, + }, + { + desc: "appropriate signed cluster object with old overwrit", + obj: testClusterConfigMap(currentFooClusterConfig, true), + config: dedent.Dedent(oldBarClusterConfig), + expected: versionStateOld, + }, + { + desc: "old signed config without an overwrite", + obj: testClusterConfigMap(oldFooClusterConfig, true), + expected: outputapi.ComponentConfigVersionState{ + Group: kubeadmapiv1.GroupName, + CurrentVersion: "", // The config is treated as if it's missing + PreferredVersion: currentClusterConfigVersion, + }, + }, + { + desc: "old signed config with appropriate overwrite", + obj: testClusterConfigMap(oldFooClusterConfig, true), + config: dedent.Dedent(currentBarClusterConfig), + expected: versionStateCurrent, + }, + { + desc: "old signed config with old overwrite", + obj: testClusterConfigMap(oldFooClusterConfig, true), + config: dedent.Dedent(oldBarClusterConfig), + expected: versionStateOld, + }, + } + + for _, test := range cases { + t.Run(test.desc, func(t *testing.T) { + client := clientsetfake.NewSimpleClientset(test.obj) + + docmap, err := kubeadmutil.SplitYAMLDocuments([]byte(test.config)) + if err != nil { + t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) + } + + clusterCfg := testClusterCfg() + + got, err := GetVersionStates(clusterCfg, client, docmap) + if err != nil { + t.Errorf("unexpected error: %v", err) + } else if len(got) != 1 { + t.Errorf("got %d, but expected only a single result: %v", len(got), got) + } else if got[0] != test.expected { + t.Errorf("unexpected result:\n\texpected: %v\n\tgot: %v", test.expected, got[0]) + } + }) + } + }) +} diff --git a/cmd/kubeadm/app/componentconfigs/kubelet_test.go b/cmd/kubeadm/app/componentconfigs/kubelet_test.go index b23106c4021..bf5d7ce8e6c 100644 --- a/cmd/kubeadm/app/componentconfigs/kubelet_test.go +++ b/cmd/kubeadm/app/componentconfigs/kubelet_test.go @@ -17,18 +17,16 @@ limitations under the License. package componentconfigs import ( - "crypto/sha256" "fmt" "path/filepath" "reflect" - "strings" "testing" "github.com/lithammer/dedent" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/version" + "k8s.io/apimachinery/pkg/runtime/schema" clientsetfake "k8s.io/client-go/kubernetes/fake" kubeletconfig "k8s.io/kubelet/config/v1beta1" utilpointer "k8s.io/utils/pointer" @@ -37,139 +35,17 @@ import ( kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/features" - kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" ) -// kubeletMarshalCases holds common marshal test cases for both the marshal and unmarshal tests -var kubeletMarshalCases = []struct { - name string - obj *kubeletConfig - yaml string -}{ - { - name: "Empty config", - obj: &kubeletConfig{ - configBase: configBase{ - GroupVersion: kubeletconfig.SchemeGroupVersion, - }, - config: kubeletconfig.KubeletConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeletconfig.SchemeGroupVersion.String(), - Kind: "KubeletConfiguration", - }, - }, +func testKubeletConfigMap(contents string) *v1.ConfigMap { + return &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion), + Namespace: metav1.NamespaceSystem, }, - yaml: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - authentication: - anonymous: {} - webhook: - cacheTTL: 0s - x509: {} - authorization: - webhook: - cacheAuthorizedTTL: 0s - cacheUnauthorizedTTL: 0s - cpuManagerReconcilePeriod: 0s - evictionPressureTransitionPeriod: 0s - fileCheckFrequency: 0s - httpCheckFrequency: 0s - imageMinimumGCAge: 0s - kind: KubeletConfiguration - logging: {} - nodeStatusReportFrequency: 0s - nodeStatusUpdateFrequency: 0s - runtimeRequestTimeout: 0s - streamingConnectionIdleTimeout: 0s - syncFrequency: 0s - volumeStatsAggPeriod: 0s - `), - }, - { - name: "Non empty config", - obj: &kubeletConfig{ - configBase: configBase{ - GroupVersion: kubeletconfig.SchemeGroupVersion, - }, - config: kubeletconfig.KubeletConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeletconfig.SchemeGroupVersion.String(), - Kind: "KubeletConfiguration", - }, - Address: "1.2.3.4", - Port: 12345, - RotateCertificates: true, - }, + Data: map[string]string{ + constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(contents), }, - yaml: dedent.Dedent(` - address: 1.2.3.4 - apiVersion: kubelet.config.k8s.io/v1beta1 - authentication: - anonymous: {} - webhook: - cacheTTL: 0s - x509: {} - authorization: - webhook: - cacheAuthorizedTTL: 0s - cacheUnauthorizedTTL: 0s - cpuManagerReconcilePeriod: 0s - evictionPressureTransitionPeriod: 0s - fileCheckFrequency: 0s - httpCheckFrequency: 0s - imageMinimumGCAge: 0s - kind: KubeletConfiguration - logging: {} - nodeStatusReportFrequency: 0s - nodeStatusUpdateFrequency: 0s - port: 12345 - rotateCertificates: true - runtimeRequestTimeout: 0s - streamingConnectionIdleTimeout: 0s - syncFrequency: 0s - volumeStatsAggPeriod: 0s - `), - }, -} - -func TestKubeletMarshal(t *testing.T) { - for _, test := range kubeletMarshalCases { - t.Run(test.name, func(t *testing.T) { - b, err := test.obj.Marshal() - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - got := strings.TrimSpace(string(b)) - expected := strings.TrimSpace(test.yaml) - if expected != string(got) { - t.Fatalf("Missmatch between expected and got:\nExpected:\n%s\n---\nGot:\n%s", expected, string(got)) - } - }) - } -} - -func TestKubeletUnmarshal(t *testing.T) { - for _, test := range kubeletMarshalCases { - t.Run(test.name, func(t *testing.T) { - gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(test.yaml)) - if err != nil { - t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) - } - - got := &kubeletConfig{ - configBase: configBase{ - GroupVersion: kubeletconfig.SchemeGroupVersion, - }, - } - if err = got.Unmarshal(gvkmap); err != nil { - t.Fatalf("unexpected failure of Unmarshal: %v", err) - } - - if !reflect.DeepEqual(got, test.obj) { - t.Fatalf("Missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", test.obj, got) - } - }) } } @@ -411,227 +287,43 @@ func TestKubeletDefault(t *testing.T) { } // runKubeletFromTest holds common test case data and evaluation code for kubeletHandler.From* functions -func runKubeletFromTest(t *testing.T, perform func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error)) { - tests := []struct { - name string - in string - out *kubeletConfig - expectErr bool - }{ - { - name: "Empty document map should return nothing successfully", - }, - { - name: "Non-empty non-kubelet document map returns nothing successfully", - in: dedent.Dedent(` - apiVersion: api.example.com/v1 - kind: Configuration - `), - }, - { - name: "Old kubelet version returns an error", - in: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1alpha1 - kind: KubeletConfiguration - `), - expectErr: true, - }, - { - name: "Wrong kubelet kind returns an error", - in: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: Configuration - `), - expectErr: true, - }, - { - name: "Valid kubelet only config gets loaded", - in: dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - address: 1.2.3.4 - port: 12345 - rotateCertificates: true - `), - out: &kubeletConfig{ - configBase: configBase{ - GroupVersion: kubeletHandler.GroupVersion, - userSupplied: true, - }, - config: kubeletconfig.KubeletConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeletHandler.GroupVersion.String(), - Kind: "KubeletConfiguration", - }, - Address: "1.2.3.4", - Port: 12345, - RotateCertificates: true, - }, - }, - }, - { - name: "Valid kubelet config gets loaded when coupled with an extra document", - in: dedent.Dedent(` - apiVersion: api.example.com/v1 - kind: Configuration - --- - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - address: 1.2.3.4 - port: 12345 - rotateCertificates: true - `), - out: &kubeletConfig{ - configBase: configBase{ - GroupVersion: kubeletHandler.GroupVersion, - userSupplied: true, - }, - config: kubeletconfig.KubeletConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeletHandler.GroupVersion.String(), - Kind: "KubeletConfiguration", - }, - Address: "1.2.3.4", - Port: 12345, - RotateCertificates: true, - }, - }, - }, - } +func runKubeletFromTest(t *testing.T, perform func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error)) { + const ( + kind = "KubeletConfiguration" + clusterDomain = "foo.bar" + ) - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - componentCfg, err := perform(t, test.in) - if err != nil { - if !test.expectErr { - t.Errorf("unexpected failure: %v", err) - } - } else { - if test.expectErr { - t.Error("unexpected success") - } else { - if componentCfg == nil { - if test.out != nil { - t.Error("unexpected nil result") - } - } else { - if got, ok := componentCfg.(*kubeletConfig); !ok { - t.Error("different result type") - } else { - if test.out == nil { - t.Errorf("unexpected result: %v", got) - } else { - if !reflect.DeepEqual(test.out, got) { - t.Errorf("missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", test.out, got) - } - } - } - } - } - } - }) + gvk := kubeletHandler.GroupVersion.WithKind(kind) + yaml := fmt.Sprintf("apiVersion: %s\nkind: %s\nclusterDomain: %s", kubeletHandler.GroupVersion, kind, clusterDomain) + + cfg, err := perform(gvk, yaml) + + if err != nil { + t.Fatalf("unexpected failure: %v", err) + } + if cfg == nil { + t.Fatal("no config loaded where it should have been") + } + if kubeletCfg, ok := cfg.(*kubeletConfig); !ok { + t.Fatalf("found different object type than expected: %s", reflect.TypeOf(cfg)) + } else if kubeletCfg.config.ClusterDomain != clusterDomain { + t.Fatalf("unexpected control value (clusterDomain):\n\tgot: %q\n\texpected: %q", kubeletCfg.config.ClusterDomain, clusterDomain) } } func TestKubeletFromDocumentMap(t *testing.T) { - runKubeletFromTest(t, func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error) { - gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(in)) - if err != nil { - t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) - } - - return kubeletHandler.FromDocumentMap(gvkmap) + runKubeletFromTest(t, func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) { + return kubeletHandler.FromDocumentMap(kubeadmapi.DocumentMap{ + gvk: []byte(yaml), + }) }) } func TestKubeletFromCluster(t *testing.T) { - runKubeletFromTest(t, func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error) { - clusterCfg := &kubeadmapi.ClusterConfiguration{ - KubernetesVersion: constants.CurrentKubernetesVersion.String(), - } - - k8sVersion := version.MustParseGeneric(clusterCfg.KubernetesVersion) - + runKubeletFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) { client := clientsetfake.NewSimpleClientset( - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(k8sVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: in, - }, - }, + testKubeletConfigMap(yaml), ) - - return kubeletHandler.FromCluster(client, clusterCfg) + return kubeletHandler.FromCluster(client, testClusterCfg()) }) } - -func TestGeneratedKubeletFromCluster(t *testing.T) { - testYAML := dedent.Dedent(` - apiVersion: kubelet.config.k8s.io/v1beta1 - kind: KubeletConfiguration - address: 1.2.3.4 - port: 12345 - rotateCertificates: true - `) - testYAMLHash := fmt.Sprintf("sha256:%x", sha256.Sum256([]byte(testYAML))) - // The SHA256 sum of "The quick brown fox jumps over the lazy dog" - const mismatchHash = "sha256:d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" - tests := []struct { - name string - hash string - userSupplied bool - }{ - { - name: "Matching hash means generated config", - hash: testYAMLHash, - }, - { - name: "Missmatching hash means user supplied config", - hash: mismatchHash, - userSupplied: true, - }, - { - name: "No hash means user supplied config", - userSupplied: true, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - clusterCfg := &kubeadmapi.ClusterConfiguration{ - KubernetesVersion: constants.CurrentKubernetesVersion.String(), - } - - k8sVersion := version.MustParseGeneric(clusterCfg.KubernetesVersion) - - configMap := &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.GetKubeletConfigMapName(k8sVersion), - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeletBaseConfigurationConfigMapKey: testYAML, - }, - } - - if test.hash != "" { - configMap.Annotations = map[string]string{ - constants.ComponentConfigHashAnnotationKey: test.hash, - } - } - - client := clientsetfake.NewSimpleClientset(configMap) - cfg, err := kubeletHandler.FromCluster(client, clusterCfg) - if err != nil { - t.Fatalf("unexpected failure of FromCluster: %v", err) - } - - got := cfg.IsUserSupplied() - if got != test.userSupplied { - t.Fatalf("mismatch between expected and got:\n\tExpected: %t\n\tGot: %t", test.userSupplied, got) - } - }) - } -} diff --git a/cmd/kubeadm/app/componentconfigs/kubeproxy_test.go b/cmd/kubeadm/app/componentconfigs/kubeproxy_test.go index 3cd17d9d50c..d68c4c89e16 100644 --- a/cmd/kubeadm/app/componentconfigs/kubeproxy_test.go +++ b/cmd/kubeadm/app/componentconfigs/kubeproxy_test.go @@ -17,10 +17,8 @@ limitations under the License. package componentconfigs import ( - "crypto/sha256" "fmt" "reflect" - "strings" "testing" "github.com/lithammer/dedent" @@ -31,185 +29,22 @@ import ( componentbaseconfig "k8s.io/component-base/config/v1alpha1" kubeproxyconfig "k8s.io/kube-proxy/config/v1alpha1" + "k8s.io/apimachinery/pkg/runtime/schema" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/features" - kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" ) -// kubeProxyMarshalCases holds common marshal test cases for both the marshal and unmarshal tests -var kubeProxyMarshalCases = []struct { - name string - obj *kubeProxyConfig - yaml string -}{ - { - name: "Empty config", - obj: &kubeProxyConfig{ - configBase: configBase{ - GroupVersion: kubeproxyconfig.SchemeGroupVersion, - }, - config: kubeproxyconfig.KubeProxyConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeproxyconfig.SchemeGroupVersion.String(), - Kind: "KubeProxyConfiguration", - }, - }, +func testKubeProxyConfigMap(contents string) *v1.ConfigMap { + return &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.KubeProxyConfigMap, + Namespace: metav1.NamespaceSystem, }, - yaml: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - bindAddress: "" - bindAddressHardFail: false - clientConnection: - acceptContentTypes: "" - burst: 0 - contentType: "" - kubeconfig: "" - qps: 0 - clusterCIDR: "" - configSyncPeriod: 0s - conntrack: - maxPerCore: null - min: null - tcpCloseWaitTimeout: null - tcpEstablishedTimeout: null - detectLocalMode: "" - enableProfiling: false - healthzBindAddress: "" - hostnameOverride: "" - iptables: - masqueradeAll: false - masqueradeBit: null - minSyncPeriod: 0s - syncPeriod: 0s - ipvs: - excludeCIDRs: null - minSyncPeriod: 0s - scheduler: "" - strictARP: false - syncPeriod: 0s - tcpFinTimeout: 0s - tcpTimeout: 0s - udpTimeout: 0s - kind: KubeProxyConfiguration - metricsBindAddress: "" - mode: "" - nodePortAddresses: null - oomScoreAdj: null - portRange: "" - showHiddenMetricsForVersion: "" - udpIdleTimeout: 0s - winkernel: - enableDSR: false - networkName: "" - sourceVip: "" - `), - }, - { - name: "Non empty config", - obj: &kubeProxyConfig{ - configBase: configBase{ - GroupVersion: kubeproxyconfig.SchemeGroupVersion, - }, - config: kubeproxyconfig.KubeProxyConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeproxyconfig.SchemeGroupVersion.String(), - Kind: "KubeProxyConfiguration", - }, - BindAddress: "1.2.3.4", - EnableProfiling: true, - }, + Data: map[string]string{ + constants.KubeProxyConfigMapKey: dedent.Dedent(contents), }, - yaml: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - bindAddress: 1.2.3.4 - bindAddressHardFail: false - clientConnection: - acceptContentTypes: "" - burst: 0 - contentType: "" - kubeconfig: "" - qps: 0 - clusterCIDR: "" - configSyncPeriod: 0s - conntrack: - maxPerCore: null - min: null - tcpCloseWaitTimeout: null - tcpEstablishedTimeout: null - detectLocalMode: "" - enableProfiling: true - healthzBindAddress: "" - hostnameOverride: "" - iptables: - masqueradeAll: false - masqueradeBit: null - minSyncPeriod: 0s - syncPeriod: 0s - ipvs: - excludeCIDRs: null - minSyncPeriod: 0s - scheduler: "" - strictARP: false - syncPeriod: 0s - tcpFinTimeout: 0s - tcpTimeout: 0s - udpTimeout: 0s - kind: KubeProxyConfiguration - metricsBindAddress: "" - mode: "" - nodePortAddresses: null - oomScoreAdj: null - portRange: "" - showHiddenMetricsForVersion: "" - udpIdleTimeout: 0s - winkernel: - enableDSR: false - networkName: "" - sourceVip: "" - `), - }, -} - -func TestKubeProxyMarshal(t *testing.T) { - for _, test := range kubeProxyMarshalCases { - t.Run(test.name, func(t *testing.T) { - b, err := test.obj.Marshal() - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - got := strings.TrimSpace(string(b)) - expected := strings.TrimSpace(test.yaml) - if expected != string(got) { - t.Fatalf("Missmatch between expected and got:\nExpected:\n%s\n---\nGot:\n%s", expected, string(got)) - } - }) - } -} - -func TestKubeProxyUnmarshal(t *testing.T) { - for _, test := range kubeProxyMarshalCases { - t.Run(test.name, func(t *testing.T) { - gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(test.yaml)) - if err != nil { - t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) - } - - got := &kubeProxyConfig{ - configBase: configBase{ - GroupVersion: kubeproxyconfig.SchemeGroupVersion, - }, - } - if err = got.Unmarshal(gvkmap); err != nil { - t.Fatalf("unexpected failure of Unmarshal: %v", err) - } - - if !reflect.DeepEqual(got, test.obj) { - t.Fatalf("Missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", test.obj, got) - } - }) } } @@ -331,210 +166,44 @@ func TestKubeProxyDefault(t *testing.T) { } // runKubeProxyFromTest holds common test case data and evaluation code for kubeProxyHandler.From* functions -func runKubeProxyFromTest(t *testing.T, perform func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error)) { - tests := []struct { - name string - in string - out *kubeProxyConfig - expectErr bool - }{ - { - name: "Empty document map should return nothing successfully", - }, - { - name: "Non-empty non-kube-proxy document map returns nothing successfully", - in: dedent.Dedent(` - apiVersion: api.example.com/v1 - kind: Configuration - `), - }, - { - name: "Old kube-proxy version returns an error", - in: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha0 - kind: KubeProxyConfiguration - `), - expectErr: true, - }, - { - name: "Wrong kube-proxy kind returns an error", - in: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: Configuration - `), - expectErr: true, - }, - { - name: "Valid kube-proxy only config gets loaded", - in: dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - bindAddress: 1.2.3.4 - enableProfiling: true - `), - out: &kubeProxyConfig{ - configBase: configBase{ - GroupVersion: kubeProxyHandler.GroupVersion, - userSupplied: true, - }, - config: kubeproxyconfig.KubeProxyConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeProxyHandler.GroupVersion.String(), - Kind: "KubeProxyConfiguration", - }, - BindAddress: "1.2.3.4", - EnableProfiling: true, - }, - }, - }, - { - name: "Valid kube-proxy config gets loaded when coupled with an extra document", - in: dedent.Dedent(` - apiVersion: api.example.com/v1 - kind: Configuration - --- - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - bindAddress: 1.2.3.4 - enableProfiling: true - `), - out: &kubeProxyConfig{ - configBase: configBase{ - GroupVersion: kubeProxyHandler.GroupVersion, - userSupplied: true, - }, - config: kubeproxyconfig.KubeProxyConfiguration{ - TypeMeta: metav1.TypeMeta{ - APIVersion: kubeProxyHandler.GroupVersion.String(), - Kind: "KubeProxyConfiguration", - }, - BindAddress: "1.2.3.4", - EnableProfiling: true, - }, - }, - }, - } +func runKubeProxyFromTest(t *testing.T, perform func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error)) { + const ( + kind = "KubeProxyConfiguration" + clusterCIDR = "1.2.3.4/16" + ) - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - componentCfg, err := perform(t, test.in) - if err != nil { - if !test.expectErr { - t.Errorf("unexpected failure: %v", err) - } - } else { - if test.expectErr { - t.Error("unexpected success") - } else { - if componentCfg == nil { - if test.out != nil { - t.Error("unexpected nil result") - } - } else { - if got, ok := componentCfg.(*kubeProxyConfig); !ok { - t.Error("different result type") - } else { - if test.out == nil { - t.Errorf("unexpected result: %v", got) - } else { - if !reflect.DeepEqual(test.out, got) { - t.Errorf("missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", test.out, got) - } - } - } - } - } - } - }) + gvk := kubeProxyHandler.GroupVersion.WithKind(kind) + yaml := fmt.Sprintf("apiVersion: %s\nkind: %s\nclusterCIDR: %s", kubeProxyHandler.GroupVersion, kind, clusterCIDR) + + cfg, err := perform(gvk, yaml) + + if err != nil { + t.Fatalf("unexpected failure: %v", err) + } + if cfg == nil { + t.Fatal("no config loaded where it should have been") + } + if kubeproxyCfg, ok := cfg.(*kubeProxyConfig); !ok { + t.Fatalf("found different object type than expected: %s", reflect.TypeOf(cfg)) + } else if kubeproxyCfg.config.ClusterCIDR != clusterCIDR { + t.Fatalf("unexpected control value (clusterDomain):\n\tgot: %q\n\texpected: %q", kubeproxyCfg.config.ClusterCIDR, clusterCIDR) } } func TestKubeProxyFromDocumentMap(t *testing.T) { - runKubeProxyFromTest(t, func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error) { - gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(in)) - if err != nil { - t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err) - } - - return kubeProxyHandler.FromDocumentMap(gvkmap) + runKubeProxyFromTest(t, func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) { + return kubeProxyHandler.FromDocumentMap(kubeadmapi.DocumentMap{ + gvk: []byte(yaml), + }) }) } func TestKubeProxyFromCluster(t *testing.T) { - runKubeProxyFromTest(t, func(t *testing.T, in string) (kubeadmapi.ComponentConfig, error) { + runKubeProxyFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) { client := clientsetfake.NewSimpleClientset( - &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: in, - }, - }, + testKubeProxyConfigMap(yaml), ) - return kubeProxyHandler.FromCluster(client, &kubeadmapi.ClusterConfiguration{}) + return kubeProxyHandler.FromCluster(client, testClusterCfg()) }) } - -func TestGeneratedKubeProxyFromCluster(t *testing.T) { - testYAML := dedent.Dedent(` - apiVersion: kubeproxy.config.k8s.io/v1alpha1 - kind: KubeProxyConfiguration - bindAddress: 1.2.3.4 - enableProfiling: true - `) - testYAMLHash := fmt.Sprintf("sha256:%x", sha256.Sum256([]byte(testYAML))) - // The SHA256 sum of "The quick brown fox jumps over the lazy dog" - const mismatchHash = "sha256:d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" - tests := []struct { - name string - hash string - userSupplied bool - }{ - { - name: "Matching hash means generated config", - hash: testYAMLHash, - }, - { - name: "Missmatching hash means user supplied config", - hash: mismatchHash, - userSupplied: true, - }, - { - name: "No hash means user supplied config", - userSupplied: true, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - configMap := &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.KubeProxyConfigMap, - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - constants.KubeProxyConfigMapKey: testYAML, - }, - } - - if test.hash != "" { - configMap.Annotations = map[string]string{ - constants.ComponentConfigHashAnnotationKey: test.hash, - } - } - - client := clientsetfake.NewSimpleClientset(configMap) - cfg, err := kubeProxyHandler.FromCluster(client, &kubeadmapi.ClusterConfiguration{}) - if err != nil { - t.Fatalf("unexpected failure of FromCluster: %v", err) - } - - got := cfg.IsUserSupplied() - if got != test.userSupplied { - t.Fatalf("mismatch between expected and got:\n\tExpected: %t\n\tGot: %t", test.userSupplied, got) - } - }) - } -} From d023f3d25df5f3f16f8ec57324ea0765a256c605 Mon Sep 17 00:00:00 2001 From: "Rostislav M. Georgiev" Date: Mon, 22 Jun 2020 14:39:34 +0300 Subject: [PATCH 2/2] kubeadm: Cleanup and refactor the LoadJoinConfigurationFromFile test Back in the v1alpha2 days the fuzzer test needed to be disabled. To ensure that there were no config breaks and everything worked correctly extensive replacement tests were put in place that functioned as unit tests for the kubeadm config utils as well. The fuzzer test has been reenabled for a long time now and there's no need for these replacements. Hence, over time most of these were disabled, deleted and refactored. The last remnants are part of the LoadJoinConfigurationFromFile test. The test data for those old tests remains largely unused today, but it still receives updates as it contains kubelet's and kube-proxy's component configs. Updates to these configs are usually done because the maintainers of those need to add a new field. Hence, to cleanup old code and reduce maintenance burden, the last test that depends on this test data is finally refactored and cleaned up to represent a simple unit test of `LoadJoinConfigurationFromFile`. Signed-off-by: Rostislav M. Georgiev --- cmd/kubeadm/app/util/config/BUILD | 3 - .../app/util/config/initconfiguration_test.go | 21 +- .../app/util/config/joinconfiguration_test.go | 149 +++++++------ .../conversion/controlplane/internal.yaml | 208 ------------------ .../controlplane/internal_non_linux.yaml | 206 ----------------- .../conversion/controlplane/v1beta1.yaml | 170 -------------- .../controlplane/v1beta1_non_linux.yaml | 168 -------------- .../testdata/conversion/node/internal.yaml | 23 -- .../testdata/conversion/node/v1beta1.yaml | 20 -- .../testdata/conversion/node/v1beta2.yaml | 20 -- .../defaulting/controlplane/defaulted.yaml | 155 ------------- .../controlplane/defaulted_non_linux.yaml | 154 ------------- .../defaulting/controlplane/incomplete.yaml | 19 -- .../testdata/defaulting/node/defaulted.yaml | 14 -- .../testdata/defaulting/node/incomplete.yaml | 11 - .../validation/invalid_controlplanecfg.yaml | 7 - .../testdata/validation/invalid_nodecfg.yaml | 15 -- 17 files changed, 79 insertions(+), 1284 deletions(-) delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal_non_linux.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1_non_linux.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/node/internal.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta1.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta2.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted_non_linux.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/incomplete.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/defaulting/node/defaulted.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/validation/invalid_controlplanecfg.yaml delete mode 100644 cmd/kubeadm/app/util/config/testdata/validation/invalid_nodecfg.yaml diff --git a/cmd/kubeadm/app/util/config/BUILD b/cmd/kubeadm/app/util/config/BUILD index 53949fdaf95..05d06bcc9e1 100644 --- a/cmd/kubeadm/app/util/config/BUILD +++ b/cmd/kubeadm/app/util/config/BUILD @@ -56,8 +56,6 @@ go_test( embed = [":go_default_library"], deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", - "//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library", - "//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1beta2:go_default_library", "//cmd/kubeadm/app/componentconfigs:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", @@ -74,7 +72,6 @@ go_test( "//staging/src/k8s.io/client-go/testing:go_default_library", "//vendor/github.com/lithammer/dedent:go_default_library", "//vendor/github.com/pkg/errors:go_default_library", - "//vendor/github.com/pmezard/go-difflib/difflib:go_default_library", "//vendor/sigs.k8s.io/yaml:go_default_library", ], ) diff --git a/cmd/kubeadm/app/util/config/initconfiguration_test.go b/cmd/kubeadm/app/util/config/initconfiguration_test.go index 9a46ea75478..435a3401e91 100644 --- a/cmd/kubeadm/app/util/config/initconfiguration_test.go +++ b/cmd/kubeadm/app/util/config/initconfiguration_test.go @@ -23,8 +23,6 @@ import ( "path/filepath" "testing" - "github.com/pmezard/go-difflib/difflib" - "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" @@ -32,24 +30,11 @@ import ( "sigs.k8s.io/yaml" ) -func diff(expected, actual []byte) string { - // Write out the diff - var diffBytes bytes.Buffer - difflib.WriteUnifiedDiff(&diffBytes, difflib.UnifiedDiff{ - A: difflib.SplitLines(string(expected)), - B: difflib.SplitLines(string(actual)), - FromFile: "expected", - ToFile: "actual", - Context: 3, - }) - return diffBytes.String() -} - func TestLoadInitConfigurationFromFile(t *testing.T) { // Create temp folder for the test case tmpdir, err := ioutil.TempDir("", "") if err != nil { - t.Fatalf("Couldn't create tmpdir") + t.Fatalf("Couldn't create tmpdir: %v", err) } defer os.RemoveAll(tmpdir) @@ -100,7 +85,7 @@ func TestLoadInitConfigurationFromFile(t *testing.T) { cfgPath := filepath.Join(tmpdir, rt.name) err := ioutil.WriteFile(cfgPath, rt.fileContents, 0644) if err != nil { - t.Errorf("Couldn't create file") + t.Errorf("Couldn't create file: %v", err) return } @@ -116,7 +101,7 @@ func TestLoadInitConfigurationFromFile(t *testing.T) { } if obj == nil { - t.Errorf("Unexpected nil return value") + t.Error("Unexpected nil return value") } } }) diff --git a/cmd/kubeadm/app/util/config/joinconfiguration_test.go b/cmd/kubeadm/app/util/config/joinconfiguration_test.go index cd9649ccbcd..5d52eb30011 100644 --- a/cmd/kubeadm/app/util/config/joinconfiguration_test.go +++ b/cmd/kubeadm/app/util/config/joinconfiguration_test.go @@ -17,100 +17,103 @@ limitations under the License. package config import ( - "bytes" "io/ioutil" + "os" + "path/filepath" "testing" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" - kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1" - kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" - kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" -) - -const ( - nodeV1beta1YAML = "testdata/conversion/node/v1beta1.yaml" - nodeV1beta2YAML = "testdata/conversion/node/v1beta2.yaml" - nodeInternalYAML = "testdata/conversion/node/internal.yaml" - nodeIncompleteYAML = "testdata/defaulting/node/incomplete.yaml" - nodeDefaultedYAML = "testdata/defaulting/node/defaulted.yaml" - nodeInvalidYAML = "testdata/validation/invalid_nodecfg.yaml" + "github.com/lithammer/dedent" ) func TestLoadJoinConfigurationFromFile(t *testing.T) { + // Create temp folder for the test case + tmpdir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("Couldn't create tmpdir: %v", err) + } + defer os.RemoveAll(tmpdir) + + // cfgFiles is in cluster_test.go var tests = []struct { - name, in, out string - groupVersion schema.GroupVersion - expectedErr bool + name string + fileContents string + expectErr bool }{ - // These tests are reading one file, loading it using LoadJoinConfigurationFromFile that all of kubeadm is using for unmarshal of our API types, - // and then marshals the internal object to the expected groupVersion - { // v1beta1 -> internal - name: "v1beta1ToInternal", - in: nodeV1beta1YAML, - out: nodeInternalYAML, - groupVersion: kubeadm.SchemeGroupVersion, + { + name: "empty file causes error", + expectErr: true, }, - { // v1beta1 -> internal -> v1beta1 - name: "v1beta1Tov1beta1", - in: nodeV1beta1YAML, - out: nodeV1beta1YAML, - groupVersion: kubeadmapiv1beta1.SchemeGroupVersion, + { + name: "Invalid v1beta1 causes error", + fileContents: dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1beta1 + kind: JoinConfiguration + `), + expectErr: true, }, - { // v1beta2 -> internal - name: "v1beta2ToInternal", - in: nodeV1beta2YAML, - out: nodeInternalYAML, - groupVersion: kubeadm.SchemeGroupVersion, + { + name: "valid v1beta1 is loaded", + fileContents: dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1beta1 + kind: JoinConfiguration + caCertPath: /etc/kubernetes/pki/ca.crt + discovery: + bootstrapToken: + apiServerEndpoint: kube-apiserver:6443 + token: abcdef.0123456789abcdef + unsafeSkipCAVerification: true + timeout: 5m0s + tlsBootstrapToken: abcdef.0123456789abcdef + `), }, - { // v1beta2 -> internal -> v1beta2 - name: "v1beta2Tov1beta2", - in: nodeV1beta2YAML, - out: nodeV1beta2YAML, - groupVersion: kubeadmapiv1beta2.SchemeGroupVersion, + { + name: "Invalid v1beta2 causes error", + fileContents: dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1beta2 + kind: JoinConfiguration + `), + expectErr: true, }, - // These tests are reading one file that has only a subset of the fields populated, loading it using LoadJoinConfigurationFromFile, - // and then marshals the internal object to the expected groupVersion - { // v1beta2 -> default -> validate -> internal -> v1beta2 - name: "incompleteYAMLToDefaultedv1beta2", - in: nodeIncompleteYAML, - out: nodeDefaultedYAML, - groupVersion: kubeadmapiv1beta2.SchemeGroupVersion, - }, - { // v1beta2 -> validation should fail - name: "invalidYAMLShouldFail", - in: nodeInvalidYAML, - expectedErr: true, + { + name: "valid v1beta2 is loaded", + fileContents: dedent.Dedent(` + apiVersion: kubeadm.k8s.io/v1beta2 + kind: JoinConfiguration + caCertPath: /etc/kubernetes/pki/ca.crt + discovery: + bootstrapToken: + apiServerEndpoint: kube-apiserver:6443 + token: abcdef.0123456789abcdef + unsafeSkipCAVerification: true + timeout: 5m0s + tlsBootstrapToken: abcdef.0123456789abcdef + `), }, } for _, rt := range tests { t.Run(rt.name, func(t2 *testing.T) { - - internalcfg, err := LoadJoinConfigurationFromFile(rt.in) + cfgPath := filepath.Join(tmpdir, rt.name) + err := ioutil.WriteFile(cfgPath, []byte(rt.fileContents), 0644) if err != nil { - if rt.expectedErr { + t.Errorf("Couldn't create file: %v", err) + return + } + + obj, err := LoadJoinConfigurationFromFile(cfgPath) + if rt.expectErr { + if err == nil { + t.Error("Unexpected success") + } + } else { + if err != nil { + t.Errorf("Error reading file: %v", err) return } - t2.Fatalf("couldn't unmarshal test data: %v", err) - } else if rt.expectedErr { - t2.Fatalf("expected error, but no error returned") - } - actual, err := kubeadmutil.MarshalToYamlForCodecs(internalcfg, rt.groupVersion, scheme.Codecs) - if err != nil { - t2.Fatalf("couldn't marshal internal object: %v", err) - } - - expected, err := ioutil.ReadFile(rt.out) - if err != nil { - t2.Fatalf("couldn't read test data: %v", err) - } - - if !bytes.Equal(expected, actual) { - t2.Errorf("the expected and actual output differs.\n\tin: %s\n\tout: %s\n\tgroupversion: %s\n\tdiff: \n%s\n", - rt.in, rt.out, rt.groupVersion.String(), diff(expected, actual)) + if obj == nil { + t.Error("Unexpected nil return value") + } } }) } diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal.yaml deleted file mode 100644 index 32dad2254bc..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal.yaml +++ /dev/null @@ -1,208 +0,0 @@ -APIServer: - CertSANs: null - ExtraArgs: - authorization-mode: Node,RBAC,Webhook - ExtraVolumes: - - HostPath: /host/read-only - MountPath: /mount/read-only - Name: ReadOnlyVolume - PathType: "" - ReadOnly: true - - HostPath: /host/writable - MountPath: /mount/writable - Name: WritableVolume - PathType: "" - ReadOnly: false - TimeoutForControlPlane: 4m0s -BootstrapTokens: -- Description: "" - Expires: null - Groups: - - system:bootstrappers:kubeadm:default-node-token - TTL: 24h0m0s - Token: s73ybu.6tw6wnqgp5z0wb77 - Usages: - - signing - - authentication -CIImageRepository: "" -CertificatesDir: /etc/kubernetes/pki -ClusterName: kubernetes -ComponentConfigs: - KubeProxy: - BindAddress: 0.0.0.0 - BindAddressHardFail: false - ClientConnection: - AcceptContentTypes: "" - Burst: 10 - ContentType: application/vnd.kubernetes.protobuf - Kubeconfig: /var/lib/kube-proxy/kubeconfig.conf - QPS: 5 - ClusterCIDR: "" - ConfigSyncPeriod: 15m0s - Conntrack: - MaxPerCore: 32768 - Min: 131072 - TCPCloseWaitTimeout: 1h0m0s - TCPEstablishedTimeout: 24h0m0s - EnableProfiling: false - FeatureGates: - ServiceNodeExclusion: true - SupportIPVSProxyMode: true - HealthzBindAddress: 0.0.0.0:10256 - HostnameOverride: "" - IPTables: - MasqueradeAll: false - MasqueradeBit: 14 - MinSyncPeriod: 0s - SyncPeriod: 30s - IPVS: - ExcludeCIDRs: null - MinSyncPeriod: 0s - Scheduler: "" - SyncPeriod: 30s - MetricsBindAddress: 127.0.0.1:10249 - Mode: iptables - NodePortAddresses: null - OOMScoreAdj: -999 - PortRange: "" - UDPIdleTimeout: 250ms - Winkernel: - EnableDSR: false - NetworkName: "" - SourceVip: "" - Kubelet: - Address: 1.2.3.4 - AllowedUnsafeSysctls: null - Authentication: - Anonymous: - Enabled: false - Webhook: - CacheTTL: 2m0s - Enabled: true - X509: - ClientCAFile: /etc/kubernetes/pki/ca.crt - Authorization: - Mode: Webhook - Webhook: - CacheAuthorizedTTL: 5m0s - CacheUnauthorizedTTL: 30s - CPUCFSQuota: true - CPUCFSQuotaPeriod: 0s - CPUManagerPolicy: none - CPUManagerReconcilePeriod: 10s - CgroupDriver: cgroupfs - CgroupRoot: "" - CgroupsPerQOS: true - ClusterDNS: - - 10.96.0.10 - ClusterDomain: cluster.local - ConfigMapAndSecretChangeDetectionStrategy: Watch - ContainerLogMaxFiles: 5 - ContainerLogMaxSize: 10Mi - ContentType: application/vnd.kubernetes.protobuf - EnableContentionProfiling: false - EnableControllerAttachDetach: true - EnableDebuggingHandlers: true - EnforceNodeAllocatable: - - pods - EventBurst: 10 - EventRecordQPS: 5 - EvictionHard: - imagefs.available: 15% - memory.available: 100Mi - nodefs.available: 10% - nodefs.inodesFree: 5% - EvictionMaxPodGracePeriod: 0 - EvictionMinimumReclaim: null - EvictionPressureTransitionPeriod: 5m0s - EvictionSoft: null - EvictionSoftGracePeriod: null - FailSwapOn: true - FeatureGates: null - FileCheckFrequency: 20s - HTTPCheckFrequency: 20s - HairpinMode: promiscuous-bridge - HealthzBindAddress: 127.0.0.1 - HealthzPort: 10248 - IPTablesDropBit: 15 - IPTablesMasqueradeBit: 14 - ImageGCHighThresholdPercent: 85 - ImageGCLowThresholdPercent: 80 - ImageMinimumGCAge: 2m0s - KubeAPIBurst: 10 - KubeAPIQPS: 5 - KubeReserved: null - KubeReservedCgroup: "" - KubeletCgroups: "" - MakeIPTablesUtilChains: true - MaxOpenFiles: 1000000 - MaxPods: 110 - NodeLeaseDurationSeconds: 40 - NodeStatusReportFrequency: 1m0s - NodeStatusUpdateFrequency: 10s - OOMScoreAdj: -999 - PodCIDR: "" - PodPidsLimit: -1 - PodsPerCore: 0 - Port: 10250 - ProtectKernelDefaults: false - QOSReserved: null - ReadOnlyPort: 0 - RegistryBurst: 10 - RegistryPullQPS: 5 - ResolverConfig: /etc/resolv.conf - RotateCertificates: true - RuntimeRequestTimeout: 2m0s - SerializeImagePulls: true - ServerTLSBootstrap: false - StaticPodPath: /etc/kubernetes/manifests - StaticPodURL: "" - StaticPodURLHeader: null - StreamingConnectionIdleTimeout: 4h0m0s - SyncFrequency: 1m0s - SystemCgroups: "" - SystemReserved: null - SystemReservedCgroup: "" - TLSCertFile: "" - TLSCipherSuites: null - TLSMinVersion: "" - TLSPrivateKeyFile: "" - VolumeStatsAggPeriod: 1m0s -ControlPlaneEndpoint: "" -ControllerManager: - ExtraArgs: null - ExtraVolumes: null -DNS: - ImageRepository: "" - ImageTag: "" - Type: CoreDNS -Etcd: - External: null - Local: - DataDir: /var/lib/etcd - ExtraArgs: null - ImageRepository: "" - ImageTag: "" - PeerCertSANs: null - ServerCertSANs: null -FeatureGates: null -ImageRepository: k8s.gcr.io -KubernetesVersion: v1.12.2 -LocalAPIEndpoint: - AdvertiseAddress: 192.168.2.2 - BindPort: 6443 -Networking: - DNSDomain: cluster.local - PodSubnet: "" - ServiceSubnet: 10.96.0.0/12 -NodeRegistration: - CRISocket: /var/run/dockershim.sock - KubeletExtraArgs: null - Name: control-plane-1 - Taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master -Scheduler: - ExtraArgs: null - ExtraVolumes: null -UseHyperKubeImage: true diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal_non_linux.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal_non_linux.yaml deleted file mode 100644 index 6c67924061e..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/internal_non_linux.yaml +++ /dev/null @@ -1,206 +0,0 @@ -APIServer: - CertSANs: null - ExtraArgs: - authorization-mode: Node,RBAC,Webhook - ExtraVolumes: - - HostPath: /host/read-only - MountPath: /mount/read-only - Name: ReadOnlyVolume - PathType: "" - ReadOnly: true - - HostPath: /host/writable - MountPath: /mount/writable - Name: WritableVolume - PathType: "" - ReadOnly: false - TimeoutForControlPlane: 4m0s -BootstrapTokens: -- Description: "" - Expires: null - Groups: - - system:bootstrappers:kubeadm:default-node-token - TTL: 24h0m0s - Token: s73ybu.6tw6wnqgp5z0wb77 - Usages: - - signing - - authentication -CIImageRepository: "" -CertificatesDir: /etc/kubernetes/pki -ClusterName: kubernetes -ComponentConfigs: - KubeProxy: - BindAddress: 0.0.0.0 - BindAddressHardFail: false - ClientConnection: - AcceptContentTypes: "" - Burst: 10 - ContentType: application/vnd.kubernetes.protobuf - Kubeconfig: /var/lib/kube-proxy/kubeconfig.conf - QPS: 5 - ClusterCIDR: "" - ConfigSyncPeriod: 15m0s - Conntrack: - MaxPerCore: 32768 - Min: 131072 - TCPCloseWaitTimeout: 1h0m0s - TCPEstablishedTimeout: 24h0m0s - EnableProfiling: false - FeatureGates: - ServiceNodeExclusion: true - SupportIPVSProxyMode: true - HealthzBindAddress: 0.0.0.0:10256 - HostnameOverride: "" - IPTables: - MasqueradeAll: false - MasqueradeBit: 14 - MinSyncPeriod: 0s - SyncPeriod: 30s - IPVS: - ExcludeCIDRs: null - MinSyncPeriod: 0s - Scheduler: "" - SyncPeriod: 30s - MetricsBindAddress: 127.0.0.1:10249 - Mode: iptables - NodePortAddresses: null - OOMScoreAdj: -999 - PortRange: "" - UDPIdleTimeout: 250ms - Winkernel: - EnableDSR: false - NetworkName: "" - SourceVip: "" - Kubelet: - Address: 1.2.3.4 - Authentication: - Anonymous: - Enabled: false - Webhook: - CacheTTL: 2m0s - Enabled: true - X509: - ClientCAFile: /etc/kubernetes/pki/ca.crt - Authorization: - Mode: Webhook - Webhook: - CacheAuthorizedTTL: 5m0s - CacheUnauthorizedTTL: 30s - CPUCFSQuota: true - CPUCFSQuotaPeriod: 0s - CPUManagerPolicy: none - CPUManagerReconcilePeriod: 10s - CgroupDriver: cgroupfs - CgroupRoot: "" - CgroupsPerQOS: true - ClusterDNS: - - 10.96.0.10 - ClusterDomain: cluster.local - ConfigMapAndSecretChangeDetectionStrategy: Watch - ContainerLogMaxFiles: 5 - ContainerLogMaxSize: 10Mi - ContentType: application/vnd.kubernetes.protobuf - EnableContentionProfiling: false - EnableControllerAttachDetach: true - EnableDebuggingHandlers: true - EnforceNodeAllocatable: - - pods - EventBurst: 10 - EventRecordQPS: 5 - EvictionHard: - imagefs.available: 15% - memory.available: 100Mi - nodefs.available: 10% - EvictionMaxPodGracePeriod: 0 - EvictionMinimumReclaim: null - EvictionPressureTransitionPeriod: 5m0s - EvictionSoft: null - EvictionSoftGracePeriod: null - FailSwapOn: true - FeatureGates: null - FileCheckFrequency: 20s - HTTPCheckFrequency: 20s - HairpinMode: promiscuous-bridge - HealthzBindAddress: 127.0.0.1 - HealthzPort: 10248 - IPTablesDropBit: 15 - IPTablesMasqueradeBit: 14 - ImageGCHighThresholdPercent: 85 - ImageGCLowThresholdPercent: 80 - ImageMinimumGCAge: 2m0s - KubeAPIBurst: 10 - KubeAPIQPS: 5 - KubeReserved: null - KubeReservedCgroup: "" - KubeletCgroups: "" - MakeIPTablesUtilChains: true - MaxOpenFiles: 1000000 - MaxPods: 110 - NodeLeaseDurationSeconds: 40 - NodeStatusReportFrequency: 1m0s - NodeStatusUpdateFrequency: 10s - OOMScoreAdj: -999 - PodCIDR: "" - PodPidsLimit: -1 - PodsPerCore: 0 - Port: 10250 - ProtectKernelDefaults: false - QOSReserved: null - ReadOnlyPort: 0 - RegistryBurst: 10 - RegistryPullQPS: 5 - ResolverConfig: /etc/resolv.conf - RotateCertificates: true - RuntimeRequestTimeout: 2m0s - SerializeImagePulls: true - ServerTLSBootstrap: false - StaticPodPath: /etc/kubernetes/manifests - StaticPodURL: "" - StaticPodURLHeader: null - StreamingConnectionIdleTimeout: 4h0m0s - SyncFrequency: 1m0s - SystemCgroups: "" - SystemReserved: null - SystemReservedCgroup: "" - TLSCertFile: "" - TLSCipherSuites: null - TLSMinVersion: "" - TLSPrivateKeyFile: "" - VolumeStatsAggPeriod: 1m0s -ControlPlaneEndpoint: "" -ControllerManager: - ExtraArgs: null - ExtraVolumes: null -DNS: - ImageRepository: "" - ImageTag: "" - Type: CoreDNS -Etcd: - External: null - Local: - DataDir: /var/lib/etcd - ExtraArgs: null - ImageRepository: "" - ImageTag: "" - PeerCertSANs: null - ServerCertSANs: null -FeatureGates: null -ImageRepository: k8s.gcr.io -KubernetesVersion: v1.12.2 -LocalAPIEndpoint: - AdvertiseAddress: 192.168.2.2 - BindPort: 6443 -Networking: - DNSDomain: cluster.local - PodSubnet: "" - ServiceSubnet: 10.96.0.0/12 -NodeRegistration: - CRISocket: /var/run/dockershim.sock - KubeletExtraArgs: null - Name: control-plane-1 - Taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master -Scheduler: - ExtraArgs: null - ExtraVolumes: null -UseHyperKubeImage: true diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1.yaml deleted file mode 100644 index 0dbaca5917b..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1.yaml +++ /dev/null @@ -1,170 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -bootstrapTokens: -- groups: - - system:bootstrappers:kubeadm:default-node-token - token: s73ybu.6tw6wnqgp5z0wb77 - ttl: 24h0m0s - usages: - - signing - - authentication -kind: InitConfiguration -localAPIEndpoint: - advertiseAddress: 192.168.2.2 - bindPort: 6443 -nodeRegistration: - criSocket: /var/run/dockershim.sock - name: control-plane-1 - taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master ---- -apiServer: - extraArgs: - authorization-mode: Node,RBAC,Webhook - extraVolumes: - - hostPath: /host/read-only - mountPath: /mount/read-only - name: ReadOnlyVolume - readOnly: true - - hostPath: /host/writable - mountPath: /mount/writable - name: WritableVolume - timeoutForControlPlane: 4m0s -apiVersion: kubeadm.k8s.io/v1beta1 -certificatesDir: /etc/kubernetes/pki -clusterName: kubernetes -controlPlaneEndpoint: "" -controllerManager: {} -dns: - type: CoreDNS -etcd: - local: - dataDir: /var/lib/etcd -imageRepository: k8s.gcr.io -kind: ClusterConfiguration -kubernetesVersion: v1.12.2 -networking: - dnsDomain: cluster.local - podSubnet: "" - serviceSubnet: 10.96.0.0/12 -scheduler: {} -useHyperKubeImage: true ---- -apiVersion: kubeproxy.config.k8s.io/v1alpha1 -bindAddress: 0.0.0.0 -bindAddressHardFail: false -clientConnection: - acceptContentTypes: "" - burst: 10 - contentType: application/vnd.kubernetes.protobuf - kubeconfig: /var/lib/kube-proxy/kubeconfig.conf - qps: 5 -clusterCIDR: "" -configSyncPeriod: 15m0s -conntrack: - maxPerCore: 32768 - min: 131072 - tcpCloseWaitTimeout: 1h0m0s - tcpEstablishedTimeout: 24h0m0s -enableProfiling: false -featureGates: - ServiceNodeExclusion: true - SupportIPVSProxyMode: true -healthzBindAddress: 0.0.0.0:10256 -hostnameOverride: "" -iptables: - masqueradeAll: false - masqueradeBit: 14 - minSyncPeriod: 0s - syncPeriod: 30s -ipvs: - excludeCIDRs: null - minSyncPeriod: 0s - scheduler: "" - syncPeriod: 30s -kind: KubeProxyConfiguration -metricsBindAddress: 127.0.0.1:10249 -mode: iptables -nodePortAddresses: null -oomScoreAdj: -999 -portRange: "" -udpIdleTimeout: 250ms -winkernel: - enableDSR: false - networkName: "" - sourceVip: "" ---- -address: 1.2.3.4 -apiVersion: kubelet.config.k8s.io/v1beta1 -authentication: - anonymous: - enabled: false - webhook: - cacheTTL: 2m0s - enabled: true - x509: - clientCAFile: /etc/kubernetes/pki/ca.crt -authorization: - mode: Webhook - webhook: - cacheAuthorizedTTL: 5m0s - cacheUnauthorizedTTL: 30s -cgroupDriver: cgroupfs -cgroupsPerQOS: true -clusterDNS: -- 10.96.0.10 -clusterDomain: cluster.local -configMapAndSecretChangeDetectionStrategy: Watch -containerLogMaxFiles: 5 -containerLogMaxSize: 10Mi -contentType: application/vnd.kubernetes.protobuf -cpuCFSQuota: true -cpuCFSQuotaPeriod: 0s -cpuManagerPolicy: none -cpuManagerReconcilePeriod: 10s -enableControllerAttachDetach: true -enableDebuggingHandlers: true -enforceNodeAllocatable: -- pods -eventBurst: 10 -eventRecordQPS: 5 -evictionHard: - imagefs.available: 15% - memory.available: 100Mi - nodefs.available: 10% - nodefs.inodesFree: 5% -evictionPressureTransitionPeriod: 5m0s -failSwapOn: true -fileCheckFrequency: 20s -hairpinMode: promiscuous-bridge -healthzBindAddress: 127.0.0.1 -healthzPort: 10248 -httpCheckFrequency: 20s -imageGCHighThresholdPercent: 85 -imageGCLowThresholdPercent: 80 -imageMinimumGCAge: 2m0s -iptablesDropBit: 15 -iptablesMasqueradeBit: 14 -kind: KubeletConfiguration -kubeAPIBurst: 10 -kubeAPIQPS: 5 -makeIPTablesUtilChains: true -maxOpenFiles: 1000000 -maxPods: 110 -nodeLeaseDurationSeconds: 40 -nodeStatusReportFrequency: 1m0s -nodeStatusUpdateFrequency: 10s -oomScoreAdj: -999 -podPidsLimit: -1 -port: 10250 -registryBurst: 10 -registryPullQPS: 5 -resolvConf: /etc/resolv.conf -rotateCertificates: true -runtimeRequestTimeout: 2m0s -serializeImagePulls: true -staticPodPath: /etc/kubernetes/manifests -streamingConnectionIdleTimeout: 4h0m0s -syncFrequency: 1m0s -volumeStatsAggPeriod: 1m0s -allowedUnsafeSysctls: [] diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1_non_linux.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1_non_linux.yaml deleted file mode 100644 index 77dce0f33cd..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/controlplane/v1beta1_non_linux.yaml +++ /dev/null @@ -1,168 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -bootstrapTokens: -- groups: - - system:bootstrappers:kubeadm:default-node-token - token: s73ybu.6tw6wnqgp5z0wb77 - ttl: 24h0m0s - usages: - - signing - - authentication -kind: InitConfiguration -localAPIEndpoint: - advertiseAddress: 192.168.2.2 - bindPort: 6443 -nodeRegistration: - criSocket: /var/run/dockershim.sock - name: control-plane-1 - taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master ---- -apiServer: - extraArgs: - authorization-mode: Node,RBAC,Webhook - extraVolumes: - - hostPath: /host/read-only - mountPath: /mount/read-only - name: ReadOnlyVolume - readOnly: true - - hostPath: /host/writable - mountPath: /mount/writable - name: WritableVolume - timeoutForControlPlane: 4m0s -apiVersion: kubeadm.k8s.io/v1beta1 -certificatesDir: /etc/kubernetes/pki -clusterName: kubernetes -controlPlaneEndpoint: "" -controllerManager: {} -dns: - type: CoreDNS -etcd: - local: - dataDir: /var/lib/etcd -imageRepository: k8s.gcr.io -kind: ClusterConfiguration -kubernetesVersion: v1.12.2 -networking: - dnsDomain: cluster.local - podSubnet: "" - serviceSubnet: 10.96.0.0/12 -scheduler: {} -useHyperKubeImage: true ---- -apiVersion: kubeproxy.config.k8s.io/v1alpha1 -bindAddress: 0.0.0.0 -bindAddressHardFail: false -clientConnection: - acceptContentTypes: "" - burst: 10 - contentType: application/vnd.kubernetes.protobuf - kubeconfig: /var/lib/kube-proxy/kubeconfig.conf - qps: 5 -clusterCIDR: "" -configSyncPeriod: 15m0s -conntrack: - maxPerCore: 32768 - min: 131072 - tcpCloseWaitTimeout: 1h0m0s - tcpEstablishedTimeout: 24h0m0s -enableProfiling: false -featureGates: - ServiceNodeExclusion: true - SupportIPVSProxyMode: true -healthzBindAddress: 0.0.0.0:10256 -hostnameOverride: "" -iptables: - masqueradeAll: false - masqueradeBit: 14 - minSyncPeriod: 0s - syncPeriod: 30s -ipvs: - excludeCIDRs: null - minSyncPeriod: 0s - scheduler: "" - syncPeriod: 30s -kind: KubeProxyConfiguration -metricsBindAddress: 127.0.0.1:10249 -mode: iptables -nodePortAddresses: null -oomScoreAdj: -999 -portRange: "" -udpIdleTimeout: 250ms -winkernel: - enableDSR: false - networkName: "" - sourceVip: "" ---- -address: 1.2.3.4 -apiVersion: kubelet.config.k8s.io/v1beta1 -authentication: - anonymous: - enabled: false - webhook: - cacheTTL: 2m0s - enabled: true - x509: - clientCAFile: /etc/kubernetes/pki/ca.crt -authorization: - mode: Webhook - webhook: - cacheAuthorizedTTL: 5m0s - cacheUnauthorizedTTL: 30s -cgroupDriver: cgroupfs -cgroupsPerQOS: true -clusterDNS: -- 10.96.0.10 -clusterDomain: cluster.local -configMapAndSecretChangeDetectionStrategy: Watch -containerLogMaxFiles: 5 -containerLogMaxSize: 10Mi -contentType: application/vnd.kubernetes.protobuf -cpuCFSQuota: true -cpuCFSQuotaPeriod: 0s -cpuManagerPolicy: none -cpuManagerReconcilePeriod: 10s -enableControllerAttachDetach: true -enableDebuggingHandlers: true -enforceNodeAllocatable: -- pods -eventBurst: 10 -eventRecordQPS: 5 -evictionHard: - imagefs.available: 15% - memory.available: 100Mi - nodefs.available: 10% -evictionPressureTransitionPeriod: 5m0s -failSwapOn: true -fileCheckFrequency: 20s -hairpinMode: promiscuous-bridge -healthzBindAddress: 127.0.0.1 -healthzPort: 10248 -httpCheckFrequency: 20s -imageGCHighThresholdPercent: 85 -imageGCLowThresholdPercent: 80 -imageMinimumGCAge: 2m0s -iptablesDropBit: 15 -iptablesMasqueradeBit: 14 -kind: KubeletConfiguration -kubeAPIBurst: 10 -kubeAPIQPS: 5 -makeIPTablesUtilChains: true -maxOpenFiles: 1000000 -maxPods: 110 -nodeLeaseDurationSeconds: 40 -nodeStatusReportFrequency: 1m0s -nodeStatusUpdateFrequency: 10s -oomScoreAdj: -999 -podPidsLimit: -1 -port: 10250 -registryBurst: 10 -registryPullQPS: 5 -resolvConf: /etc/resolv.conf -rotateCertificates: true -runtimeRequestTimeout: 2m0s -serializeImagePulls: true -staticPodPath: /etc/kubernetes/manifests -streamingConnectionIdleTimeout: 4h0m0s -syncFrequency: 1m0s -volumeStatsAggPeriod: 1m0s diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/node/internal.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/node/internal.yaml deleted file mode 100644 index e0af329be05..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/node/internal.yaml +++ /dev/null @@ -1,23 +0,0 @@ -CACertPath: /etc/kubernetes/pki/ca.crt -ControlPlane: - CertificateKey: "" - LocalAPIEndpoint: - AdvertiseAddress: 192.168.2.2 - BindPort: 6443 -Discovery: - BootstrapToken: - APIServerEndpoint: kube-apiserver:6443 - CACertHashes: null - Token: abcdef.0123456789abcdef - UnsafeSkipCAVerification: true - File: null - TLSBootstrapToken: abcdef.0123456789abcdef - Timeout: 5m0s -NodeRegistration: - CRISocket: /var/run/dockershim.sock - IgnorePreflightErrors: null - KubeletExtraArgs: null - Name: control-plane-1 - Taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta1.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta1.yaml deleted file mode 100644 index 90bd7430140..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta1.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -caCertPath: /etc/kubernetes/pki/ca.crt -controlPlane: - localAPIEndpoint: - advertiseAddress: 192.168.2.2 - bindPort: 6443 -discovery: - bootstrapToken: - apiServerEndpoint: kube-apiserver:6443 - token: abcdef.0123456789abcdef - unsafeSkipCAVerification: true - timeout: 5m0s - tlsBootstrapToken: abcdef.0123456789abcdef -kind: JoinConfiguration -nodeRegistration: - criSocket: /var/run/dockershim.sock - name: control-plane-1 - taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta2.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta2.yaml deleted file mode 100644 index bd75a932a58..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/conversion/node/v1beta2.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta2 -caCertPath: /etc/kubernetes/pki/ca.crt -controlPlane: - localAPIEndpoint: - advertiseAddress: 192.168.2.2 - bindPort: 6443 -discovery: - bootstrapToken: - apiServerEndpoint: kube-apiserver:6443 - token: abcdef.0123456789abcdef - unsafeSkipCAVerification: true - timeout: 5m0s - tlsBootstrapToken: abcdef.0123456789abcdef -kind: JoinConfiguration -nodeRegistration: - criSocket: /var/run/dockershim.sock - name: control-plane-1 - taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted.yaml deleted file mode 100644 index 7daef54d779..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted.yaml +++ /dev/null @@ -1,155 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -bootstrapTokens: -- groups: - - system:bootstrappers:kubeadm:default-node-token - token: s73ybu.6tw6wnqgp5z0wb77 - ttl: 24h0m0s - usages: - - signing - - authentication -kind: InitConfiguration -localAPIEndpoint: - advertiseAddress: 192.168.2.2 - bindPort: 6443 -nodeRegistration: - criSocket: /var/run/criruntime.sock - name: control-plane-1 - taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master ---- -apiServer: - timeoutForControlPlane: 4m0s -apiVersion: kubeadm.k8s.io/v1beta1 -certificatesDir: /var/lib/kubernetes/pki -clusterName: kubernetes -controlPlaneEndpoint: "" -controllerManager: {} -dns: - type: CoreDNS -etcd: - local: - dataDir: /var/lib/etcd -imageRepository: my-company.com -kind: ClusterConfiguration -kubernetesVersion: v1.13.0 -networking: - dnsDomain: cluster.global - podSubnet: 10.148.0.0/16 - serviceSubnet: 10.196.0.0/12 -scheduler: {} ---- -apiVersion: kubeproxy.config.k8s.io/v1alpha1 -bindAddress: 0.0.0.0 -bindAddressHardFail: false -clientConnection: - acceptContentTypes: "" - burst: 10 - contentType: application/vnd.kubernetes.protobuf - kubeconfig: /var/lib/kube-proxy/kubeconfig.conf - qps: 5 -clusterCIDR: 10.148.0.0/16 -configSyncPeriod: 15m0s -conntrack: - maxPerCore: 32768 - min: 131072 - tcpCloseWaitTimeout: 1h0m0s - tcpEstablishedTimeout: 24h0m0s -enableProfiling: false -healthzBindAddress: 0.0.0.0:10256 -hostnameOverride: "" -iptables: - masqueradeAll: false - masqueradeBit: 14 - minSyncPeriod: 0s - syncPeriod: 30s -ipvs: - excludeCIDRs: null - minSyncPeriod: 0s - scheduler: "" - syncPeriod: 30s -kind: KubeProxyConfiguration -metricsBindAddress: 127.0.0.1:10249 -mode: "" -nodePortAddresses: null -oomScoreAdj: -999 -portRange: "" -udpIdleTimeout: 250ms -winkernel: - enableDSR: false - networkName: "" - sourceVip: "" ---- -address: 0.0.0.0 -apiVersion: kubelet.config.k8s.io/v1beta1 -authentication: - anonymous: - enabled: false - webhook: - cacheTTL: 2m0s - enabled: true - x509: - clientCAFile: /etc/kubernetes/pki/ca.crt -authorization: - mode: Webhook - webhook: - cacheAuthorizedTTL: 5m0s - cacheUnauthorizedTTL: 30s -cgroupDriver: cgroupfs -cgroupsPerQOS: true -clusterDNS: -- 10.192.0.10 -clusterDomain: cluster.global -configMapAndSecretChangeDetectionStrategy: Watch -containerLogMaxFiles: 5 -containerLogMaxSize: 10Mi -contentType: application/vnd.kubernetes.protobuf -cpuCFSQuota: true -cpuCFSQuotaPeriod: 100ms -cpuManagerPolicy: none -cpuManagerReconcilePeriod: 10s -enableControllerAttachDetach: true -enableDebuggingHandlers: true -enforceNodeAllocatable: -- pods -eventBurst: 10 -eventRecordQPS: 5 -evictionHard: - imagefs.available: 15% - memory.available: 100Mi - nodefs.available: 10% - nodefs.inodesFree: 5% -evictionPressureTransitionPeriod: 5m0s -failSwapOn: true -fileCheckFrequency: 20s -hairpinMode: promiscuous-bridge -healthzBindAddress: 127.0.0.1 -healthzPort: 10248 -httpCheckFrequency: 20s -imageGCHighThresholdPercent: 85 -imageGCLowThresholdPercent: 80 -imageMinimumGCAge: 2m0s -iptablesDropBit: 15 -iptablesMasqueradeBit: 14 -kind: KubeletConfiguration -kubeAPIBurst: 10 -kubeAPIQPS: 5 -makeIPTablesUtilChains: true -maxOpenFiles: 1000000 -maxPods: 110 -nodeLeaseDurationSeconds: 40 -nodeStatusReportFrequency: 1m0s -nodeStatusUpdateFrequency: 10s -oomScoreAdj: -999 -podPidsLimit: -1 -port: 10250 -registryBurst: 10 -registryPullQPS: 5 -resolvConf: /etc/resolv.conf -rotateCertificates: true -runtimeRequestTimeout: 2m0s -serializeImagePulls: true -staticPodPath: /etc/kubernetes/manifests -streamingConnectionIdleTimeout: 4h0m0s -syncFrequency: 1m0s -volumeStatsAggPeriod: 1m0s diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted_non_linux.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted_non_linux.yaml deleted file mode 100644 index 455c74a3af2..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/defaulted_non_linux.yaml +++ /dev/null @@ -1,154 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -bootstrapTokens: -- groups: - - system:bootstrappers:kubeadm:default-node-token - token: s73ybu.6tw6wnqgp5z0wb77 - ttl: 24h0m0s - usages: - - signing - - authentication -kind: InitConfiguration -localAPIEndpoint: - advertiseAddress: 192.168.2.2 - bindPort: 6443 -nodeRegistration: - criSocket: /var/run/criruntime.sock - name: control-plane-1 - taints: - - effect: NoSchedule - key: node-role.kubernetes.io/master ---- -apiServer: - timeoutForControlPlane: 4m0s -apiVersion: kubeadm.k8s.io/v1beta1 -certificatesDir: /var/lib/kubernetes/pki -clusterName: kubernetes -controlPlaneEndpoint: "" -controllerManager: {} -dns: - type: CoreDNS -etcd: - local: - dataDir: /var/lib/etcd -imageRepository: my-company.com -kind: ClusterConfiguration -kubernetesVersion: v1.13.0 -networking: - dnsDomain: cluster.global - podSubnet: 10.148.0.0/16 - serviceSubnet: 10.196.0.0/12 -scheduler: {} ---- -apiVersion: kubeproxy.config.k8s.io/v1alpha1 -bindAddress: 0.0.0.0 -bindAddressHardFail: false -clientConnection: - acceptContentTypes: "" - burst: 10 - contentType: application/vnd.kubernetes.protobuf - kubeconfig: /var/lib/kube-proxy/kubeconfig.conf - qps: 5 -clusterCIDR: 10.148.0.0/16 -configSyncPeriod: 15m0s -conntrack: - maxPerCore: 32768 - min: 131072 - tcpCloseWaitTimeout: 1h0m0s - tcpEstablishedTimeout: 24h0m0s -enableProfiling: false -healthzBindAddress: 0.0.0.0:10256 -hostnameOverride: "" -iptables: - masqueradeAll: false - masqueradeBit: 14 - minSyncPeriod: 0s - syncPeriod: 30s -ipvs: - excludeCIDRs: null - minSyncPeriod: 0s - scheduler: "" - syncPeriod: 30s -kind: KubeProxyConfiguration -metricsBindAddress: 127.0.0.1:10249 -mode: "" -nodePortAddresses: null -oomScoreAdj: -999 -portRange: "" -udpIdleTimeout: 250ms -winkernel: - enableDSR: false - networkName: "" - sourceVip: "" ---- -address: 0.0.0.0 -apiVersion: kubelet.config.k8s.io/v1beta1 -authentication: - anonymous: - enabled: false - webhook: - cacheTTL: 2m0s - enabled: true - x509: - clientCAFile: /etc/kubernetes/pki/ca.crt -authorization: - mode: Webhook - webhook: - cacheAuthorizedTTL: 5m0s - cacheUnauthorizedTTL: 30s -cgroupDriver: cgroupfs -cgroupsPerQOS: true -clusterDNS: -- 10.192.0.10 -clusterDomain: cluster.global -configMapAndSecretChangeDetectionStrategy: Watch -containerLogMaxFiles: 5 -containerLogMaxSize: 10Mi -contentType: application/vnd.kubernetes.protobuf -cpuCFSQuota: true -cpuCFSQuotaPeriod: 100ms -cpuManagerPolicy: none -cpuManagerReconcilePeriod: 10s -enableControllerAttachDetach: true -enableDebuggingHandlers: true -enforceNodeAllocatable: -- pods -eventBurst: 10 -eventRecordQPS: 5 -evictionHard: - imagefs.available: 15% - memory.available: 100Mi - nodefs.available: 10% -evictionPressureTransitionPeriod: 5m0s -failSwapOn: true -fileCheckFrequency: 20s -hairpinMode: promiscuous-bridge -healthzBindAddress: 127.0.0.1 -healthzPort: 10248 -httpCheckFrequency: 20s -imageGCHighThresholdPercent: 85 -imageGCLowThresholdPercent: 80 -imageMinimumGCAge: 2m0s -iptablesDropBit: 15 -iptablesMasqueradeBit: 14 -kind: KubeletConfiguration -kubeAPIBurst: 10 -kubeAPIQPS: 5 -makeIPTablesUtilChains: true -maxOpenFiles: 1000000 -maxPods: 110 -nodeLeaseDurationSeconds: 40 -nodeStatusReportFrequency: 1m0s -nodeStatusUpdateFrequency: 10s -oomScoreAdj: -999 -podPidsLimit: -1 -port: 10250 -registryBurst: 10 -registryPullQPS: 5 -resolvConf: /etc/resolv.conf -rotateCertificates: true -runtimeRequestTimeout: 2m0s -serializeImagePulls: true -staticPodPath: /etc/kubernetes/manifests -streamingConnectionIdleTimeout: 4h0m0s -syncFrequency: 1m0s -volumeStatsAggPeriod: 1m0s diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/incomplete.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/incomplete.yaml deleted file mode 100644 index f945cec6101..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/controlplane/incomplete.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -kind: InitConfiguration -bootstrapTokens: -- token: s73ybu.6tw6wnqgp5z0wb77 -localAPIEndpoint: - advertiseAddress: 192.168.2.2 -nodeRegistration: - criSocket: /var/run/criruntime.sock - name: control-plane-1 ---- -apiVersion: kubeadm.k8s.io/v1beta1 -certificatesDir: /var/lib/kubernetes/pki -imageRepository: my-company.com -kind: ClusterConfiguration -kubernetesVersion: v1.13.0 -networking: - dnsDomain: cluster.global - podSubnet: 10.148.0.0/16 - serviceSubnet: 10.196.0.0/12 \ No newline at end of file diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/node/defaulted.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/node/defaulted.yaml deleted file mode 100644 index 6de881fffd9..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/node/defaulted.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta2 -caCertPath: /etc/kubernetes/pki/ca.crt -discovery: - bootstrapToken: - apiServerEndpoint: kube-apiserver:6443 - token: abcdef.0123456789abcdef - unsafeSkipCAVerification: true - timeout: 5m0s - tlsBootstrapToken: abcdef.0123456789abcdef -kind: JoinConfiguration -nodeRegistration: - criSocket: /var/run/dockershim.sock - name: thegopher - taints: null diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml deleted file mode 100644 index fb56966e540..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta2 -discovery: - bootstrapToken: - apiServerEndpoint: kube-apiserver:6443 - token: abcdef.0123456789abcdef - unsafeSkipCAVerification: true - tlsBootstrapToken: abcdef.0123456789abcdef -kind: JoinConfiguration -nodeRegistration: - criSocket: /var/run/dockershim.sock - name: thegopher diff --git a/cmd/kubeadm/app/util/config/testdata/validation/invalid_controlplanecfg.yaml b/cmd/kubeadm/app/util/config/testdata/validation/invalid_controlplanecfg.yaml deleted file mode 100644 index 55c7fb1b5ad..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/validation/invalid_controlplanecfg.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta1 -kind: ClusterConfiguration -networking: - dnsDomain: INVALID-DOMAIN-!!!! - podSubnet: "" - serviceSubnet: 10.96.0.0/12 -useHyperKubeImage: false \ No newline at end of file diff --git a/cmd/kubeadm/app/util/config/testdata/validation/invalid_nodecfg.yaml b/cmd/kubeadm/app/util/config/testdata/validation/invalid_nodecfg.yaml deleted file mode 100644 index c4fabd135ba..00000000000 --- a/cmd/kubeadm/app/util/config/testdata/validation/invalid_nodecfg.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: kubeadm.k8s.io/v1beta2 -kind: NodeConfiguration -caCertPath: relativepath -discovery: - timeout: not-a-time - bootstrapToken: - token: invalidtoken - apiServerEndpoints: - - INVALID_URL - unsafeSkipCAVerification: false - file: - kubeConfigPath: relativepath -nodeRegistration: - criSocket: relativepath - name: NODE-1