diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 0409f212eca..06d163c4e52 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -81,16 +81,19 @@ go_library( go_test( name = "go_default_test", srcs = [ + "join_test.go", "reset_test.go", "token_test.go", "version_test.go", ], embed = [":go_default_library"], deps = [ + "//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", + "//pkg/api/legacyscheme:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 6791f9abf4d..a152c6a7fd3 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -115,21 +115,7 @@ func NewCmdJoin(out io.Writer) *cobra.Command { Short: "Run this on any machine you wish to join an existing cluster", Long: joinLongDescription, Run: func(cmd *cobra.Command, args []string) { - cfg.DiscoveryTokenAPIServers = args - - var err error - if cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString); err != nil { - kubeadmutil.CheckErr(err) - } - - legacyscheme.Scheme.Default(cfg) - internalcfg := &kubeadmapi.NodeConfiguration{} - legacyscheme.Scheme.Convert(cfg, internalcfg, nil) - - ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight) - kubeadmutil.CheckErr(err) - - j, err := NewJoin(cfgPath, args, internalcfg, ignorePreflightErrorsSet) + j, err := NewValidJoin(cfg, args, skipPreFlight, cfgPath, featureGatesString, ignorePreflightErrors) kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(j.Validate(cmd)) kubeadmutil.CheckErr(j.Run(out)) @@ -142,6 +128,27 @@ func NewCmdJoin(out io.Writer) *cobra.Command { return cmd } +// NewValidJoin validates the command line that are passed to the cobra command +func NewValidJoin(cfg *kubeadmapiext.NodeConfiguration, args []string, skipPreFlight bool, cfgPath, featureGatesString string, ignorePreflightErrors []string) (*Join, error) { + cfg.DiscoveryTokenAPIServers = args + + var err error + if cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString); err != nil { + return nil, err + } + + legacyscheme.Scheme.Default(cfg) + internalcfg := &kubeadmapi.NodeConfiguration{} + legacyscheme.Scheme.Convert(cfg, internalcfg, nil) + + ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight) + if err != nil { + return nil, err + } + + return NewJoin(cfgPath, args, internalcfg, ignorePreflightErrorsSet) +} + // AddJoinConfigFlags adds join flags bound to the config to the specified flagset func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiext.NodeConfiguration, featureGatesString *string) { flagSet.StringVar( diff --git a/cmd/kubeadm/app/cmd/join_test.go b/cmd/kubeadm/app/cmd/join_test.go new file mode 100644 index 00000000000..b0c38bc8f90 --- /dev/null +++ b/cmd/kubeadm/app/cmd/join_test.go @@ -0,0 +1,187 @@ +/* +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 ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + "k8s.io/kubernetes/pkg/api/legacyscheme" +) + +const ( + testConfig = `apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: + server: localhost:9008 + name: prod +contexts: +- context: + cluster: prod + namespace: default + user: default-service-account + name: default +current-context: default +kind: Config +preferences: {} +users: +- name: kubernetes-admin + user: + client-certificate-data: + client-key-data: +` +) + +func TestNewValidJoin(t *testing.T) { + // create temp directory + tmpDir, err := ioutil.TempDir("", "kubeadm-join-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() + + testCases := []struct { + name string + args []string + skipPreFlight bool + cfgPath string + configToWrite string + featureGatesString string + ignorePreflightErrors []string + testJoinValidate bool + testJoinRun bool + cmdPersistentFlags map[string]string + nodeConfig *kubeadm.NodeConfiguration + expectedError bool + }{ + { + name: "invalid: missing config file", + skipPreFlight: true, + cfgPath: "missing-path-to-a-config", + expectedError: true, + }, + { + name: "invalid: incorrect config file", + skipPreFlight: true, + cfgPath: configFilePath, + configToWrite: "bad-config-contents", + expectedError: true, + }, + { + name: "invalid: fail at preflight.RunJoinNodeChecks()", + skipPreFlight: false, + cfgPath: configFilePath, + configToWrite: testConfig, + expectedError: true, + }, + { + name: "invalid: incorrect ignorePreflight argument", + skipPreFlight: true, + cfgPath: configFilePath, + configToWrite: testConfig, + ignorePreflightErrors: []string{"some-unsupported-preflight-arg"}, + expectedError: true, + }, + { + name: "invalid: incorrect featureGatesString", + featureGatesString: "bad-feature-gate-string", + expectedError: true, + }, + { + name: "invalid: fail Join.Validate() with wrong flags", + skipPreFlight: true, + cfgPath: configFilePath, + configToWrite: testConfig, + testJoinValidate: true, + cmdPersistentFlags: map[string]string{ + "config": "some-config", + "node-name": "some-node-name", + }, + expectedError: true, + }, + { + name: "invalid: fail Join.Validate() with wrong node configuration", + skipPreFlight: true, + cfgPath: configFilePath, + configToWrite: testConfig, + testJoinValidate: true, + expectedError: true, + }, + { + name: "invalid: fail Join.Run() with invalid node config", + skipPreFlight: true, + cfgPath: configFilePath, + configToWrite: testConfig, + testJoinRun: true, + expectedError: true, + }, + } + + var out bytes.Buffer + cfg := &kubeadmapiext.NodeConfiguration{} + legacyscheme.Scheme.Default(cfg) + + errorFormat := "Test case %q: NewValidJoin expected error: %v, saw: %v, error: %v" + + for _, tc := range testCases { + if _, err = cfgFile.WriteString(tc.configToWrite); err != nil { + t.Fatalf("Unable to write file %q: %v", tc.cfgPath, err) + } + + join, err := NewValidJoin(cfg, tc.args, tc.skipPreFlight, tc.cfgPath, tc.featureGatesString, tc.ignorePreflightErrors) + cmd := NewCmdJoin(&out) + + if tc.cmdPersistentFlags != nil { + for key, value := range tc.cmdPersistentFlags { + cmd.PersistentFlags().Set(key, value) + } + } + if tc.nodeConfig != nil { + join.cfg = tc.nodeConfig + } + + // test Join.Run() + if err == nil && tc.testJoinRun { + err = join.Run(&out) + if (err != nil) != tc.expectedError { + t.Fatalf(errorFormat, tc.name, tc.expectedError, (err != nil), err) + } + // test Join.Validate() + } else if err == nil && tc.testJoinValidate { + if err = join.Validate(cmd); (err != nil) != tc.expectedError { + t.Fatalf(errorFormat, tc.name, tc.expectedError, (err != nil), err) + } + // check error for NewValidJoin() + } else if (err != nil) != tc.expectedError { + t.Fatalf(errorFormat, tc.name, tc.expectedError, (err != nil), err) + } + } +}