Merge pull request #72513 from fabriziopandini/init-unit-test

Add kubeadm init unit test
pull/564/head
Kubernetes Prow Robot 2019-01-07 03:46:33 -08:00 committed by GitHub
commit b06462f040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 173 additions and 5 deletions

View File

@ -80,6 +80,7 @@ go_test(
srcs = [ srcs = [
"completion_test.go", "completion_test.go",
"config_test.go", "config_test.go",
"init_test.go",
"join_test.go", "join_test.go",
"reset_test.go", "reset_test.go",
"token_test.go", "token_test.go",
@ -91,8 +92,10 @@ go_test(
"//cmd/kubeadm/app/apis/kubeadm/scheme: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/v1beta1:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
"//cmd/kubeadm/app/cmd/options:go_default_library",
"//cmd/kubeadm/app/componentconfigs:go_default_library", "//cmd/kubeadm/app/componentconfigs:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/features:go_default_library",
"//cmd/kubeadm/app/preflight:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library",
"//cmd/kubeadm/app/util:go_default_library", "//cmd/kubeadm/app/util:go_default_library",
"//cmd/kubeadm/app/util/config:go_default_library", "//cmd/kubeadm/app/util/config:go_default_library",

View File

@ -82,7 +82,7 @@ func NewKubeadmCommand(in io.Reader, out, err io.Writer) *cobra.Command {
cmds.AddCommand(NewCmdCompletion(out, "")) cmds.AddCommand(NewCmdCompletion(out, ""))
cmds.AddCommand(NewCmdConfig(out)) cmds.AddCommand(NewCmdConfig(out))
cmds.AddCommand(NewCmdInit(out)) cmds.AddCommand(NewCmdInit(out, nil))
cmds.AddCommand(NewCmdJoin(out)) cmds.AddCommand(NewCmdJoin(out))
cmds.AddCommand(NewCmdReset(in, out)) cmds.AddCommand(NewCmdReset(in, out))
cmds.AddCommand(NewCmdVersion(out)) cmds.AddCommand(NewCmdVersion(out))

View File

@ -124,8 +124,12 @@ type initData struct {
} }
// NewCmdInit returns "kubeadm init" command. // NewCmdInit returns "kubeadm init" command.
func NewCmdInit(out io.Writer) *cobra.Command { // NB. initOptions is exposed as parameter for allowing unit testing of
initOptions := newInitOptions() // the newInitOptions method, that implements all the command options validation logic
func NewCmdInit(out io.Writer, initOptions *initOptions) *cobra.Command {
if initOptions == nil {
initOptions = newInitOptions()
}
initRunner := workflow.NewRunner() initRunner := workflow.NewRunner()
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -192,7 +196,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.InitConfiguration, featureGatesString *string) { func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.InitConfiguration, featureGatesString *string) {
flagSet.StringVar( flagSet.StringVar(
&cfg.LocalAPIEndpoint.AdvertiseAddress, options.APIServerAdvertiseAddress, cfg.LocalAPIEndpoint.AdvertiseAddress, &cfg.LocalAPIEndpoint.AdvertiseAddress, options.APIServerAdvertiseAddress, cfg.LocalAPIEndpoint.AdvertiseAddress,
"The IP address the API Server will advertise it's listening on. Specify '0.0.0.0' to use the address of the default network interface.", "The IP address the API Server will advertise it's listening on. If not set the default network interface will be used.",
) )
flagSet.Int32Var( flagSet.Int32Var(
&cfg.LocalAPIEndpoint.BindPort, options.APIServerBindPort, cfg.LocalAPIEndpoint.BindPort, &cfg.LocalAPIEndpoint.BindPort, options.APIServerBindPort, cfg.LocalAPIEndpoint.BindPort,
@ -289,7 +293,9 @@ func newInitData(cmd *cobra.Command, options *initOptions, out io.Writer) (initD
} }
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors) ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors)
kubeadmutil.CheckErr(err) if err != nil {
return initData{}, err
}
if err = validation.ValidateMixedArguments(cmd.Flags()); err != nil { if err = validation.ValidateMixedArguments(cmd.Flags()); err != nil {
return initData{}, err return initData{}, err

View File

@ -0,0 +1,159 @@
/*
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 cmd
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
)
const (
testInitConfig = `---
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "1.2.3.4"
bootstrapTokens:
- token: "abcdef.0123456789abcdef"
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: someName
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
controlPlaneEndpoint: "3.4.5.6"
`
)
func TestNewInitData(t *testing.T) {
// create temp directory
tmpDir, err := ioutil.TempDir("", "kubeadm-init-test")
if err != nil {
t.Errorf("Unable to create temporary directory: %v", err)
}
defer os.RemoveAll(tmpDir)
// create config file
configFilePath := filepath.Join(tmpDir, "test-config-file")
cfgFile, err := os.Create(configFilePath)
if err != nil {
t.Errorf("Unable to create file %q: %v", configFilePath, err)
}
defer cfgFile.Close()
if _, err = cfgFile.WriteString(testInitConfig); err != nil {
t.Fatalf("Unable to write file %q: %v", configFilePath, err)
}
testCases := []struct {
name string
args []string
flags map[string]string
validate func(*testing.T, *initData)
expectError bool
}{
// Init data passed using flags
{
name: "pass without any flag (use defaults)",
},
{
name: "fail if unknown feature gates flag are passed",
flags: map[string]string{
options.FeatureGatesString: "unknown=true",
},
expectError: true,
},
{
name: "fail if deprecetes feature gates are set",
flags: map[string]string{
options.FeatureGatesString: fmt.Sprintf("%s=true", features.CoreDNS),
},
expectError: true,
},
{
name: "fails if invalid preflight checks are provided",
flags: map[string]string{
options.IgnorePreflightErrors: "all,something-else",
},
expectError: true,
},
// Init data passed using config file
{
name: "Pass with config from file",
flags: map[string]string{
options.CfgPath: configFilePath,
},
},
{
name: "--cri-socket and --node-name flags override config from file",
flags: map[string]string{
options.CfgPath: configFilePath,
options.NodeCRISocket: "/var/run/crio/crio.sock",
options.NodeName: "anotherName",
},
validate: func(t *testing.T, data *initData) {
// validate that cri-socket and node-name are overwritten
if data.cfg.NodeRegistration.CRISocket != "/var/run/crio/crio.sock" {
t.Errorf("Invalid NodeRegistration.CRISocket")
}
if data.cfg.NodeRegistration.Name != "anotherName" {
t.Errorf("Invalid NodeRegistration.Name")
}
},
},
{
name: "fail if mixedArguments are passed",
flags: map[string]string{
options.CfgPath: configFilePath,
options.APIServerAdvertiseAddress: "1.2.3.4",
},
expectError: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// initialize an external init option and inject it to the init cmd
initOptions := newInitOptions()
cmd := NewCmdInit(nil, initOptions)
// sets cmd flags (that will be reflected on the init options)
for f, v := range tc.flags {
cmd.Flags().Set(f, v)
}
// test newInitData method
data, err := newInitData(cmd, initOptions, nil)
if err != nil && !tc.expectError {
t.Fatalf("newInitData returned unexpected error: %v", err)
}
if err == nil && tc.expectError {
t.Fatalf("newInitData didn't return error when expected")
}
// exec additional validation on the returned value
if tc.validate != nil {
tc.validate(t, &data)
}
})
}
}