diff --git a/cmd/kubeadm/app/util/config/BUILD b/cmd/kubeadm/app/util/config/BUILD index aa2d49a672d..70e324bb7ae 100644 --- a/cmd/kubeadm/app/util/config/BUILD +++ b/cmd/kubeadm/app/util/config/BUILD @@ -40,6 +40,7 @@ go_library( go_test( name = "go_default_test", srcs = [ + "cluster_test.go", "common_test.go", "masterconfig_test.go", "nodeconfig_test.go", @@ -52,7 +53,12 @@ go_test( "//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/util:go_default_library", + "//cmd/kubeadm/app/util/apiclient:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/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", "//vendor/github.com/pmezard/go-difflib/difflib:go_default_library", ], ) diff --git a/cmd/kubeadm/app/util/config/cluster.go b/cmd/kubeadm/app/util/config/cluster.go index c7c37d559be..239f0520acc 100644 --- a/cmd/kubeadm/app/util/config/cluster.go +++ b/cmd/kubeadm/app/util/config/cluster.go @@ -28,8 +28,6 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/constants" ) -// TODO: Add unit tests for this file - // FetchConfigFromFileOrCluster fetches configuration required for upgrading your cluster from a file (which has precedence) or a ConfigMap in the cluster func FetchConfigFromFileOrCluster(client clientset.Interface, w io.Writer, logPrefix, cfgPath string) (*kubeadmapi.InitConfiguration, error) { // Load the configuration from a file or the cluster diff --git a/cmd/kubeadm/app/util/config/cluster_test.go b/cmd/kubeadm/app/util/config/cluster_test.go new file mode 100644 index 00000000000..36ad8e6ec46 --- /dev/null +++ b/cmd/kubeadm/app/util/config/cluster_test.go @@ -0,0 +1,201 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "fmt" + "os" + "strings" + "testing" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientset "k8s.io/client-go/kubernetes" + clientsetfake "k8s.io/client-go/kubernetes/fake" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" +) + +func TestFetchConfigFromFileOrCluster(t *testing.T) { + var tests = []struct { + name string + cfgPath string + testCfg *kubeadmapi.InitConfiguration + expectErr string + }{ + { + name: "fetch valid config from configMap", + testCfg: &kubeadmapi.InitConfiguration{ + KubernetesVersion: "v1.10.3", + API: kubeadm.API{ + AdvertiseAddress: "1.2.3.4", + BindPort: 6443, + }, + Etcd: kubeadm.Etcd{ + Local: &kubeadm.LocalEtcd{ + DataDir: "/some/path", + }, + }, + Networking: kubeadm.Networking{ + ServiceSubnet: "10.96.0.1/12", + DNSDomain: "cluster.local", + PodSubnet: "10.0.1.15/16", + }, + CertificatesDir: "/some/other/cert/dir", + BootstrapTokens: []kubeadm.BootstrapToken{ + { + Token: &kubeadm.BootstrapTokenString{ + ID: "abcdef", + Secret: "abcdef0123456789", + }, + }, + }, + NodeRegistration: kubeadm.NodeRegistrationOptions{ + Name: "node-foo", + CRISocket: "/var/run/custom-cri.sock", + }, + }, + }, + { + name: "fetch invalid config from configMap", + testCfg: &kubeadmapi.InitConfiguration{ + KubernetesVersion: "v1.10.3", + API: kubeadm.API{ + AdvertiseAddress: "1.2.3.4", + BindPort: 6443, + }, + Etcd: kubeadm.Etcd{ + Local: &kubeadm.LocalEtcd{ + DataDir: "/some/path", + }, + }, + Networking: kubeadm.Networking{ + ServiceSubnet: "10.96.0.1/12", + DNSDomain: "cluster.local", + PodSubnet: "10.0.1.15", + }, + CertificatesDir: "/some/other/cert/dir", + BootstrapTokens: []kubeadm.BootstrapToken{ + { + Token: &kubeadm.BootstrapTokenString{ + ID: "abcdef", + Secret: "abcdef0123456789", + }, + }, + }, + NodeRegistration: kubeadm.NodeRegistrationOptions{ + Name: "node-foo", + CRISocket: "/var/run/custom-cri.sock", + }, + }, + expectErr: "couldn't parse subnet", + }, + { + name: "fetch valid config from cfgPath", + cfgPath: "testdata/conversion/master/v1alpha2.yaml", + testCfg: &kubeadmapi.InitConfiguration{ + KubernetesVersion: "v1.10.3", + API: kubeadm.API{ + AdvertiseAddress: "1.2.3.4", + BindPort: 6443, + }, + Etcd: kubeadm.Etcd{ + Local: &kubeadm.LocalEtcd{ + DataDir: "/some/path", + }, + }, + Networking: kubeadm.Networking{ + ServiceSubnet: "10.96.0.1/12", + DNSDomain: "cluster.local", + PodSubnet: "10.0.1.15", + }, + CertificatesDir: "/some/other/cert/dir", + BootstrapTokens: []kubeadm.BootstrapToken{ + { + Token: &kubeadm.BootstrapTokenString{ + ID: "abcdef", + Secret: "abcdef0123456789", + }, + }, + }, + NodeRegistration: kubeadm.NodeRegistrationOptions{ + Name: "node-foo", + CRISocket: "/var/run/custom-cri.sock", + }, + }, + }, + { + name: "fetch invalid config from cfgPath", + cfgPath: "testdata/validation/invalid_mastercfg.yaml", + expectErr: "was not of the form", + }, + { + name: "fetch config from not exist cfgPath", + cfgPath: "testdata231/defaulting/master/defaulted.yaml", + expectErr: "no such file or directory", + }, + { + name: "fetch config when no configMap and no cfgPath", + expectErr: "not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := clientsetfake.NewSimpleClientset() + if tt.testCfg != nil { + err := createConfigMapWithCfg(tt.testCfg, client) + if err != nil { + t.Errorf("UploadConfiguration failed err: %v", err) + } + } + _, err := FetchConfigFromFileOrCluster(client, os.Stdout, "upgrade/config", tt.cfgPath) + if len(tt.expectErr) == 0 { + if err != nil { + t.Fatalf("expected no err, but got err: %v", err) + } + } else if !strings.Contains(err.Error(), tt.expectErr) { + t.Errorf("expected contain err: %v, but got err: %v", tt.expectErr, err) + } + }) + } +} + +// createConfigMapWithCfg create a ConfigMap with InitConfiguration for TestFetchConfigFromFileOrCluster +func createConfigMapWithCfg(cfgToCreate *kubeadmapi.InitConfiguration, client clientset.Interface) error { + cfgYaml, err := MarshalKubeadmConfigObject(cfgToCreate) + if err != nil { + fmt.Println("err", err.Error()) + return err + } + + err = apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubeadmconstants.InitConfigurationConfigMap, + Namespace: metav1.NamespaceSystem, + }, + Data: map[string]string{ + kubeadmconstants.InitConfigurationConfigMapKey: string(cfgYaml), + }, + }) + if err != nil { + return err + } + return nil +}