From 690c7e578b341a34dbb9b72f6355655a373dc423 Mon Sep 17 00:00:00 2001 From: Mike Danese Date: Tue, 8 Nov 2016 11:27:16 -0800 Subject: [PATCH] kubeadm: refactor discovery behind an interface --- cmd/kubeadm/app/apis/kubeadm/types.go | 33 ++-- .../app/apis/kubeadm/v1alpha1/defaults.go | 19 +- .../app/apis/kubeadm/v1alpha1/types.go | 28 ++- .../kubeadm/v1alpha1/zz_generated.defaults.go | 5 - cmd/kubeadm/app/apis/kubeadm/validation/BUILD | 18 ++ .../app/apis/kubeadm/validation/validation.go | 70 +++++++ cmd/kubeadm/app/cmd/BUILD | 3 + cmd/kubeadm/app/cmd/init.go | 73 +++---- cmd/kubeadm/app/cmd/join.go | 80 ++++---- cmd/kubeadm/app/cmd/token.go | 6 +- cmd/kubeadm/app/discovery/BUILD | 37 ++++ cmd/kubeadm/app/discovery/discovery.go | 31 +++ cmd/kubeadm/app/discovery/file/BUILD | 15 ++ cmd/kubeadm/app/discovery/file/file.go | 30 +++ cmd/kubeadm/app/discovery/flags.go | 83 ++++++++ cmd/kubeadm/app/discovery/flags_test.go | 83 ++++++++ cmd/kubeadm/app/discovery/https/BUILD | 15 ++ cmd/kubeadm/app/discovery/https/https.go | 30 +++ cmd/kubeadm/app/discovery/token/BUILD | 15 ++ cmd/kubeadm/app/discovery/token/token.go | 46 +++++ cmd/kubeadm/app/master/discovery.go | 13 +- cmd/kubeadm/app/master/discovery_test.go | 59 +----- cmd/kubeadm/app/master/kubeconfig.go | 2 +- cmd/kubeadm/app/master/manifests.go | 2 +- cmd/kubeadm/app/master/manifests_test.go | 8 +- cmd/kubeadm/app/master/tokens.go | 36 ++-- cmd/kubeadm/app/master/tokens_test.go | 87 +++------ cmd/kubeadm/app/node/bootstrap.go | 4 +- cmd/kubeadm/app/node/bootstrap_test.go | 2 +- cmd/kubeadm/app/node/csr.go | 54 +++++- cmd/kubeadm/app/node/csr_test.go | 2 +- cmd/kubeadm/app/node/discovery.go | 7 +- cmd/kubeadm/app/node/discovery_test.go | 8 +- cmd/kubeadm/app/preflight/checks.go | 9 +- cmd/kubeadm/app/util/BUILD | 1 + cmd/kubeadm/app/util/tokens.go | 81 ++++---- cmd/kubeadm/app/util/tokens_test.go | 183 +++--------------- cmd/kubeadm/test/token_test.go | 4 +- pkg/api/testing/fuzzer.go | 8 +- 39 files changed, 784 insertions(+), 506 deletions(-) create mode 100644 cmd/kubeadm/app/apis/kubeadm/validation/BUILD create mode 100644 cmd/kubeadm/app/apis/kubeadm/validation/validation.go create mode 100644 cmd/kubeadm/app/discovery/BUILD create mode 100644 cmd/kubeadm/app/discovery/discovery.go create mode 100644 cmd/kubeadm/app/discovery/file/BUILD create mode 100644 cmd/kubeadm/app/discovery/file/file.go create mode 100644 cmd/kubeadm/app/discovery/flags.go create mode 100644 cmd/kubeadm/app/discovery/flags_test.go create mode 100644 cmd/kubeadm/app/discovery/https/BUILD create mode 100644 cmd/kubeadm/app/discovery/https/https.go create mode 100644 cmd/kubeadm/app/discovery/token/BUILD create mode 100644 cmd/kubeadm/app/discovery/token/token.go diff --git a/cmd/kubeadm/app/apis/kubeadm/types.go b/cmd/kubeadm/app/apis/kubeadm/types.go index 762a51fceb4..2c3dac03686 100644 --- a/cmd/kubeadm/app/apis/kubeadm/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/types.go @@ -33,7 +33,6 @@ type EnvParams struct { type MasterConfiguration struct { metav1.TypeMeta - Secrets Secrets API API Discovery Discovery Etcd Etcd @@ -45,11 +44,27 @@ type MasterConfiguration struct { type API struct { AdvertiseAddresses []string ExternalDNSNames []string - BindPort int32 + Port int32 } type Discovery struct { - BindPort int32 + HTTPS *HTTPSDiscovery + File *FileDiscovery + Token *TokenDiscovery +} + +type HTTPSDiscovery struct { + URL string +} + +type FileDiscovery struct { + Path string +} + +type TokenDiscovery struct { + ID string + Secret string + Addresses []string } type Networking struct { @@ -65,20 +80,10 @@ type Etcd struct { KeyFile string } -type Secrets struct { - GivenToken string // dot-separated `.` set by the user - TokenID string // optional on master side, will be generated if not specified - Token []byte // optional on master side, will be generated if not specified - BearerToken string // set based on Token -} - type NodeConfiguration struct { metav1.TypeMeta - MasterAddresses []string - Secrets Secrets - APIPort int32 - DiscoveryPort int32 + Discovery Discovery } // ClusterInfo TODO add description diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go index 3bc2ac3233a..11ea1d1b8b9 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go @@ -33,7 +33,6 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { RegisterDefaults(scheme) return scheme.AddDefaultingFuncs( SetDefaults_MasterConfiguration, - SetDefaults_NodeConfiguration, ) } @@ -42,12 +41,8 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) { obj.KubernetesVersion = DefaultKubernetesVersion } - if obj.API.BindPort == 0 { - obj.API.BindPort = DefaultAPIBindPort - } - - if obj.Discovery.BindPort == 0 { - obj.Discovery.BindPort = DefaultDiscoveryBindPort + if obj.API.Port == 0 { + obj.API.Port = DefaultAPIBindPort } if obj.Networking.ServiceSubnet == "" { @@ -58,13 +53,3 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) { obj.Networking.DNSDomain = DefaultServiceDNSDomain } } - -func SetDefaults_NodeConfiguration(obj *NodeConfiguration) { - if obj.APIPort == 0 { - obj.APIPort = DefaultAPIBindPort - } - - if obj.DiscoveryPort == 0 { - obj.DiscoveryPort = DefaultDiscoveryBindPort - } -} diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go index 08e1627f65b..f05cc6c8c3d 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go @@ -23,10 +23,9 @@ import ( type MasterConfiguration struct { metav1.TypeMeta `json:",inline"` - Secrets Secrets `json:"secrets"` API API `json:"api"` - Etcd Etcd `json:"etcd"` Discovery Discovery `json:"discovery"` + Etcd Etcd `json:"etcd"` Networking Networking `json:"networking"` KubernetesVersion string `json:"kubernetesVersion"` CloudProvider string `json:"cloudProvider"` @@ -35,11 +34,27 @@ type MasterConfiguration struct { type API struct { AdvertiseAddresses []string `json:"advertiseAddresses"` ExternalDNSNames []string `json:"externalDNSNames"` - BindPort int32 `json:"bindPort"` + Port int32 `json:"port"` } type Discovery struct { - BindPort int32 `json:"bindPort"` + HTTPS *HTTPSDiscovery `json:"https"` + File *FileDiscovery `json:"file"` + Token *TokenDiscovery `json:"token"` +} + +type HTTPSDiscovery struct { + URL string `json:"url"` +} + +type FileDiscovery struct { + Path string `json:"path"` +} + +type TokenDiscovery struct { + ID string `json:"id"` + Secret string `json:"secret"` + Addresses []string `json:"addresses"` } type Networking struct { @@ -65,10 +80,7 @@ type Secrets struct { type NodeConfiguration struct { metav1.TypeMeta `json:",inline"` - MasterAddresses []string `json:"masterAddresses"` - Secrets Secrets `json:"secrets"` - APIPort int32 `json:"apiPort"` - DiscoveryPort int32 `json:"discoveryPort"` + Discovery Discovery `json:"discovery"` } // ClusterInfo TODO add description diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.defaults.go index ead6c7e92bf..184f6f9e96c 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.defaults.go @@ -29,14 +29,9 @@ import ( // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { scheme.AddTypeDefaultingFunc(&MasterConfiguration{}, func(obj interface{}) { SetObjectDefaults_MasterConfiguration(obj.(*MasterConfiguration)) }) - scheme.AddTypeDefaultingFunc(&NodeConfiguration{}, func(obj interface{}) { SetObjectDefaults_NodeConfiguration(obj.(*NodeConfiguration)) }) return nil } func SetObjectDefaults_MasterConfiguration(in *MasterConfiguration) { SetDefaults_MasterConfiguration(in) } - -func SetObjectDefaults_NodeConfiguration(in *NodeConfiguration) { - SetDefaults_NodeConfiguration(in) -} diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD new file mode 100644 index 00000000000..8eb248f4b59 --- /dev/null +++ b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD @@ -0,0 +1,18 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["validation.go"], + tags = ["automanaged"], + deps = [ + "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//pkg/util/validation/field:go_default_library", + ], +) diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go new file mode 100644 index 00000000000..260fde5e291 --- /dev/null +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -0,0 +1,70 @@ +/* +Copyright 2016 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 validation + +import ( + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + "k8s.io/kubernetes/pkg/util/validation/field" +) + +func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateDiscovery(&c.Discovery, field.NewPath("discovery"))...) + return allErrs +} + +func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateDiscovery(&c.Discovery, field.NewPath("discovery"))...) + return allErrs +} + +func ValidateDiscovery(c *kubeadm.Discovery, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + var count int + if c.Token != nil { + allErrs = append(allErrs, ValidateTokenDiscovery(c.Token, fldPath)...) + count++ + } + if c.File != nil { + allErrs = append(allErrs, ValidateFileDiscovery(c.File, fldPath)...) + count++ + } + if c.HTTPS != nil { + allErrs = append(allErrs, ValidateHTTPSDiscovery(c.HTTPS, fldPath)...) + count++ + } + if count != 1 { + allErrs = append(allErrs, field.Invalid(fldPath, nil, "exactly one discovery strategy can be provided")) + } + return allErrs +} + +func ValidateFileDiscovery(c *kubeadm.FileDiscovery, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + return allErrs +} + +func ValidateHTTPSDiscovery(c *kubeadm.HTTPSDiscovery, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + return allErrs +} + +func ValidateTokenDiscovery(c *kubeadm.TokenDiscovery, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + return allErrs +} diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 87e6b604c7a..29c26339e40 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -22,12 +22,15 @@ go_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/cmd/flags:go_default_library", + "//cmd/kubeadm/app/discovery:go_default_library", "//cmd/kubeadm/app/master:go_default_library", "//cmd/kubeadm/app/node:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", "//cmd/kubeadm/app/util:go_default_library", "//pkg/api:go_default_library", + "//pkg/client/unversioned/clientcmd/api:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", "//pkg/runtime:go_default_library", "//pkg/util/flag:go_default_library", diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index dc1a0688575..ac2824951db 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -17,9 +17,7 @@ limitations under the License. package cmd import ( - "bytes" "fmt" - "html/template" "io" "io/ioutil" @@ -28,7 +26,9 @@ import ( kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "k8s.io/kubernetes/cmd/kubeadm/app/cmd/flags" + "k8s.io/kubernetes/cmd/kubeadm/app/discovery" kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" @@ -37,18 +37,6 @@ import ( netutil "k8s.io/kubernetes/pkg/util/net" ) -const ( - joinArgsTemplateLiteral = `--token={{.Cfg.Secrets.GivenToken -}} - {{if ne .Cfg.API.BindPort .DefaultAPIBindPort -}} - {{" --api-port="}}{{.Cfg.API.BindPort -}} - {{end -}} - {{if ne .Cfg.Discovery.BindPort .DefaultDiscoveryBindPort -}} - {{" --discovery-port="}}{{.Cfg.Discovery.BindPort -}} - {{end -}} - {{" "}}{{index .Cfg.API.AdvertiseAddresses 0 -}} -` -) - var ( initDoneMsgf = dedent.Dedent(` Your Kubernetes master has initialized successfully! @@ -59,7 +47,7 @@ var ( You can now join any number of machines by running the following on each node: - kubeadm join %s + kubeadm join --discovery %s `) ) @@ -78,14 +66,11 @@ func NewCmdInit(out io.Writer) *cobra.Command { Run: func(cmd *cobra.Command, args []string) { i, err := NewInit(cfgPath, &cfg, skipPreFlight) kubeadmutil.CheckErr(err) + kubeadmutil.CheckErr(i.Validate()) kubeadmutil.CheckErr(i.Run(out)) }, } - cmd.PersistentFlags().StringVar( - &cfg.Secrets.GivenToken, "token", cfg.Secrets.GivenToken, - "Shared secret used to secure cluster bootstrap; if none is provided, one will be generated for you", - ) cmd.PersistentFlags().StringSliceVar( &cfg.API.AdvertiseAddresses, "api-advertise-addresses", cfg.API.AdvertiseAddresses, "The IP addresses to advertise, in case autodetection fails", @@ -148,14 +133,9 @@ func NewCmdInit(out io.Writer) *cobra.Command { "skip preflight checks normally run before modifying the system", ) - cmd.PersistentFlags().Int32Var( - &cfg.API.BindPort, "api-port", cfg.API.BindPort, - "Port for API to bind to", - ) - - cmd.PersistentFlags().Int32Var( - &cfg.Discovery.BindPort, "discovery-port", cfg.Discovery.BindPort, - "Port for JWS discovery service to bind to", + cmd.PersistentFlags().Var( + discovery.NewDiscoveryValue(&cfg.Discovery), "discovery", + "The discovery method kubeadm will use for connecting nodes to the master", ) return cmd @@ -228,17 +208,17 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight return &Init{cfg: cfg}, nil } -// joinArgsData denotes a data object which is needed by function generateJoinArgs to generate kubeadm join arguments. -type joinArgsData struct { - Cfg *kubeadmapi.MasterConfiguration - DefaultAPIBindPort int32 - DefaultDiscoveryBindPort int32 +func (i *Init) Validate() error { + return validation.ValidateMasterConfiguration(i.cfg).ToAggregate() } // Run executes master node provisioning, including certificates, needed static pod manifests, etc. func (i *Init) Run(out io.Writer) error { - if err := kubemaster.CreateTokenAuthFile(&i.cfg.Secrets); err != nil { - return err + + if i.cfg.Discovery.Token != nil { + if err := kubemaster.CreateTokenAuthFile(i.cfg.Discovery.Token); err != nil { + return err + } } if err := kubemaster.WriteStaticPodManifests(i.cfg); err != nil { @@ -275,34 +255,25 @@ func (i *Init) Run(out io.Writer) error { return err } - schedulePodsOnMaster := false - if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client, schedulePodsOnMaster); err != nil { + if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client, false); err != nil { return err } - if err := kubemaster.CreateDiscoveryDeploymentAndSecret(i.cfg, client, caCert); err != nil { - return err + if i.cfg.Discovery.Token != nil { + if err := kubemaster.CreateDiscoveryDeploymentAndSecret(i.cfg, client, caCert); err != nil { + return err + } } if err := kubemaster.CreateEssentialAddons(i.cfg, client); err != nil { return err } - data := joinArgsData{i.cfg, kubeadmapiext.DefaultAPIBindPort, kubeadmapiext.DefaultDiscoveryBindPort} - if joinArgs, err := generateJoinArgs(data); err != nil { - return err - } else { - fmt.Fprintf(out, initDoneMsgf, joinArgs) - } + fmt.Fprintf(out, initDoneMsgf, generateJoinArgs(i.cfg)) return nil } // generateJoinArgs generates kubeadm join arguments -func generateJoinArgs(data joinArgsData) (string, error) { - joinArgsTemplate := template.Must(template.New("joinArgsTemplate").Parse(joinArgsTemplateLiteral)) - var b bytes.Buffer - if err := joinArgsTemplate.Execute(&b, data); err != nil { - return "", err - } - return b.String(), nil +func generateJoinArgs(cfg *kubeadmapi.MasterConfiguration) string { + return discovery.NewDiscoveryValue(&cfg.Discovery).String() } diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 92cce00a23f..ef3ae3356dc 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -26,10 +26,13 @@ import ( kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" + "k8s.io/kubernetes/cmd/kubeadm/app/discovery" kubenode "k8s.io/kubernetes/cmd/kubeadm/app/node" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/pkg/api" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" "k8s.io/kubernetes/pkg/runtime" ) @@ -60,15 +63,11 @@ func NewCmdJoin(out io.Writer) *cobra.Command { Run: func(cmd *cobra.Command, args []string) { j, err := NewJoin(cfgPath, args, &cfg, skipPreFlight) kubeadmutil.CheckErr(err) + kubeadmutil.CheckErr(j.Validate()) kubeadmutil.CheckErr(j.Run(out)) }, } - cmd.PersistentFlags().StringVar( - &cfg.Secrets.GivenToken, "token", cfg.Secrets.GivenToken, - "(required) Shared secret used to secure bootstrap. Must match the output of 'kubeadm init'", - ) - cmd.PersistentFlags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file") cmd.PersistentFlags().BoolVar( @@ -76,14 +75,9 @@ func NewCmdJoin(out io.Writer) *cobra.Command { "skip preflight checks normally run before modifying the system", ) - cmd.PersistentFlags().Int32Var( - &cfg.APIPort, "api-port", cfg.APIPort, - "(optional) API server port on the master", - ) - - cmd.PersistentFlags().Int32Var( - &cfg.DiscoveryPort, "discovery-port", cfg.DiscoveryPort, - "(optional) Discovery port on the master", + cmd.PersistentFlags().Var( + discovery.NewDiscoveryValue(&cfg.Discovery), "discovery", + "The discovery method kubeadm will use for connecting nodes to the master", ) return cmd @@ -107,14 +101,6 @@ func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, s } } - if len(args) == 0 && len(cfg.MasterAddresses) == 0 { - return nil, fmt.Errorf("must specify master address (see --help)") - } - cfg.MasterAddresses = append(cfg.MasterAddresses, args...) - if len(cfg.MasterAddresses) > 1 { - return nil, fmt.Errorf("must not specify more than one master address (see --help)") - } - if !skipPreFlight { fmt.Println("[preflight] Running pre-flight checks") @@ -134,40 +120,46 @@ func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, s // Try to start the kubelet service in case it's inactive preflight.TryStartKubelet() - ok, err := kubeadmutil.UseGivenTokenIfValid(&cfg.Secrets) - if !ok { - if err != nil { - return nil, fmt.Errorf("%v (see --help)", err) - } - return nil, fmt.Errorf("Must specify --token (see --help)") - } - return &Join{cfg: cfg}, nil } +func (j *Join) Validate() error { + return validation.ValidateNodeConfiguration(j.cfg).ToAggregate() +} + // Run executes worked node provisioning and tries to join an existing cluster. func (j *Join) Run(out io.Writer) error { - clusterInfo, err := kubenode.RetrieveTrustedClusterInfo(j.cfg) + clusterInfo, err := kubenode.RetrieveTrustedClusterInfo(j.cfg.Discovery.Token) if err != nil { return err } - connectionDetails, err := kubenode.EstablishMasterConnection(j.cfg, clusterInfo) - if err != nil { - return err + var cfg *clientcmdapi.Config + // TODO: delete this first block when we move Token to the discovery interface + if j.cfg.Discovery.Token != nil { + connectionDetails, err := kubenode.EstablishMasterConnection(j.cfg.Discovery.Token, clusterInfo) + if err != nil { + return err + } + err = kubenode.CheckForNodeNameDuplicates(connectionDetails) + if err != nil { + return err + } + cfg, err = kubenode.PerformTLSBootstrapDeprecated(connectionDetails) + if err != nil { + return err + } + } else { + cfg, err = discovery.For(j.cfg.Discovery) + if err != nil { + return err + } + if err := kubenode.PerformTLSBootstrap(cfg); err != nil { + return err + } } - err = kubenode.CheckForNodeNameDuplicates(connectionDetails) - if err != nil { - return err - } - - kubeconfig, err := kubenode.PerformTLSBootstrap(connectionDetails) - if err != nil { - return err - } - - err = kubeadmutil.WriteKubeconfigIfNotExists("kubelet", kubeconfig) + err = kubeadmutil.WriteKubeconfigIfNotExists("kubelet", cfg) if err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/token.go b/cmd/kubeadm/app/cmd/token.go index 87765105207..7f4a7404961 100644 --- a/cmd/kubeadm/app/cmd/token.go +++ b/cmd/kubeadm/app/cmd/token.go @@ -75,12 +75,12 @@ func NewCmdTokenGenerate(out io.Writer) *cobra.Command { } func RunGenerateToken(out io.Writer) error { - s := &kubeadmapi.Secrets{} - err := util.GenerateToken(s) + d := &kubeadmapi.TokenDiscovery{} + err := util.GenerateToken(d) if err != nil { return err } - fmt.Fprintln(out, s.GivenToken) + fmt.Fprintln(out, util.BearerToken(d)) return nil } diff --git a/cmd/kubeadm/app/discovery/BUILD b/cmd/kubeadm/app/discovery/BUILD new file mode 100644 index 00000000000..4149130f709 --- /dev/null +++ b/cmd/kubeadm/app/discovery/BUILD @@ -0,0 +1,37 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_library( + name = "go_default_library", + srcs = [ + "discovery.go", + "flags.go", + ], + tags = ["automanaged"], + deps = [ + "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//cmd/kubeadm/app/discovery/file:go_default_library", + "//cmd/kubeadm/app/discovery/https:go_default_library", + "//cmd/kubeadm/app/discovery/token:go_default_library", + "//pkg/client/unversioned/clientcmd/api:go_default_library", + "//vendor:github.com/spf13/pflag", + ], +) + +go_test( + name = "go_default_test", + srcs = ["flags_test.go"], + library = "go_default_library", + tags = ["automanaged"], + deps = [ + "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//vendor:github.com/davecgh/go-spew/spew", + ], +) diff --git a/cmd/kubeadm/app/discovery/discovery.go b/cmd/kubeadm/app/discovery/discovery.go new file mode 100644 index 00000000000..ef5e3087067 --- /dev/null +++ b/cmd/kubeadm/app/discovery/discovery.go @@ -0,0 +1,31 @@ +/* +Copyright 2016 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 discovery + +import ( + "fmt" + + kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +func For(c kubeadmapi.Discovery) (*clientcmdapi.Config, error) { + switch { + default: + return nil, fmt.Errorf("unimplemented") + } +} diff --git a/cmd/kubeadm/app/discovery/file/BUILD b/cmd/kubeadm/app/discovery/file/BUILD new file mode 100644 index 00000000000..8d492ba1e1b --- /dev/null +++ b/cmd/kubeadm/app/discovery/file/BUILD @@ -0,0 +1,15 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["file.go"], + tags = ["automanaged"], + deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], +) diff --git a/cmd/kubeadm/app/discovery/file/file.go b/cmd/kubeadm/app/discovery/file/file.go new file mode 100644 index 00000000000..a68254267b7 --- /dev/null +++ b/cmd/kubeadm/app/discovery/file/file.go @@ -0,0 +1,30 @@ +/* +Copyright 2016 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 file + +import ( + "net/url" + + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" +) + +func Parse(u *url.URL, c *kubeadm.Discovery) error { + c.File = &kubeadm.FileDiscovery{ + Path: u.Path, + } + return nil +} diff --git a/cmd/kubeadm/app/discovery/flags.go b/cmd/kubeadm/app/discovery/flags.go new file mode 100644 index 00000000000..cec184b0e91 --- /dev/null +++ b/cmd/kubeadm/app/discovery/flags.go @@ -0,0 +1,83 @@ +/* +Copyright 2016 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 discovery + +import ( + "fmt" + "net/url" + "strings" + + "github.com/spf13/pflag" + + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + "k8s.io/kubernetes/cmd/kubeadm/app/discovery/file" + "k8s.io/kubernetes/cmd/kubeadm/app/discovery/https" + "k8s.io/kubernetes/cmd/kubeadm/app/discovery/token" +) + +type discoveryValue struct { + v *kubeadm.Discovery +} + +func NewDiscoveryValue(d *kubeadm.Discovery) pflag.Value { + return &discoveryValue{ + v: d, + } +} + +func (d *discoveryValue) String() string { + switch { + case d.v.HTTPS != nil: + return d.v.HTTPS.URL + case d.v.File != nil: + return "file://" + d.v.File.Path + case d.v.Token != nil: + return fmt.Sprintf("token://%s:%s@%s", d.v.Token.ID, d.v.Token.Secret, strings.Join(d.v.Token.Addresses, ",")) + default: + return "unknown" + } +} + +func (d *discoveryValue) Set(s string) error { + var kd kubeadm.Discovery + if err := ParseURL(&kd, s); err != nil { + return err + } + *d.v = kd + return nil +} + +func (d *discoveryValue) Type() string { + return "discovery" +} + +func ParseURL(d *kubeadm.Discovery, s string) error { + u, err := url.Parse(s) + if err != nil { + return err + } + switch u.Scheme { + case "https": + return https.Parse(u, d) + case "file": + return file.Parse(u, d) + case "token": + return token.Parse(u, d) + default: + return fmt.Errorf("unknown discovery scheme") + } +} diff --git a/cmd/kubeadm/app/discovery/flags_test.go b/cmd/kubeadm/app/discovery/flags_test.go new file mode 100644 index 00000000000..dde621ed99b --- /dev/null +++ b/cmd/kubeadm/app/discovery/flags_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2016 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 discovery + +import ( + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" +) + +func TestParseURL(t *testing.T) { + cases := []struct { + url string + expect kubeadm.Discovery + expectErr bool + }{ + { + url: "token://", + expect: kubeadm.Discovery{ + Token: &kubeadm.TokenDiscovery{}, + }, + }, + { + url: "token://c05de9:ab224260fb3cd718@192.168.0.1:6555,191.168.0.2:6443", + expect: kubeadm.Discovery{ + Token: &kubeadm.TokenDiscovery{ + ID: "c05de9", + Secret: "ab224260fb3cd718", + Addresses: []string{ + "192.168.0.1:6555", + "191.168.0.2:6443", + }, + }, + }, + }, + { + url: "file:///foo/bar/baz", + expect: kubeadm.Discovery{ + File: &kubeadm.FileDiscovery{ + Path: "/foo/bar/baz", + }, + }, + }, + { + url: "https://storage.googleapis.com/kubeadm-disco/clusters/217651295213", + expect: kubeadm.Discovery{ + HTTPS: &kubeadm.HTTPSDiscovery{ + URL: "https://storage.googleapis.com/kubeadm-disco/clusters/217651295213", + }, + }, + }, + } + for _, c := range cases { + var d kubeadm.Discovery + if err := ParseURL(&d, c.url); err != nil { + if !c.expectErr { + t.Errorf("unexpected error parsing discovery url: %v", err) + } + continue + } + if !reflect.DeepEqual(d, c.expect) { + t.Errorf("expected discovery config to be equeal but got:\n\ta: %s\n\tb: %s", spew.Sdump(d), spew.Sdump(c.expect)) + } + + } +} diff --git a/cmd/kubeadm/app/discovery/https/BUILD b/cmd/kubeadm/app/discovery/https/BUILD new file mode 100644 index 00000000000..a446e35edb0 --- /dev/null +++ b/cmd/kubeadm/app/discovery/https/BUILD @@ -0,0 +1,15 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["https.go"], + tags = ["automanaged"], + deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], +) diff --git a/cmd/kubeadm/app/discovery/https/https.go b/cmd/kubeadm/app/discovery/https/https.go new file mode 100644 index 00000000000..132f9bd8a4d --- /dev/null +++ b/cmd/kubeadm/app/discovery/https/https.go @@ -0,0 +1,30 @@ +/* +Copyright 2016 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 https + +import ( + "net/url" + + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" +) + +func Parse(u *url.URL, c *kubeadm.Discovery) error { + c.HTTPS = &kubeadm.HTTPSDiscovery{ + URL: u.String(), + } + return nil +} diff --git a/cmd/kubeadm/app/discovery/token/BUILD b/cmd/kubeadm/app/discovery/token/BUILD new file mode 100644 index 00000000000..5915210ec09 --- /dev/null +++ b/cmd/kubeadm/app/discovery/token/BUILD @@ -0,0 +1,15 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["token.go"], + tags = ["automanaged"], + deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], +) diff --git a/cmd/kubeadm/app/discovery/token/token.go b/cmd/kubeadm/app/discovery/token/token.go new file mode 100644 index 00000000000..1560204f4fc --- /dev/null +++ b/cmd/kubeadm/app/discovery/token/token.go @@ -0,0 +1,46 @@ +/* +Copyright 2016 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 token + +import ( + "net/url" + "strings" + + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" +) + +func Parse(u *url.URL, c *kubeadm.Discovery) error { + var ( + hosts []string + tokenID, token string + ) + if u.Host != "" { + hosts = strings.Split(u.Host, ",") + } + if u.User != nil { + if p, ok := u.User.Password(); ok { + tokenID = u.User.Username() + token = p + } + } + c.Token = &kubeadm.TokenDiscovery{ + ID: tokenID, + Secret: token, + Addresses: hosts, + } + return nil +} diff --git a/cmd/kubeadm/app/master/discovery.go b/cmd/kubeadm/app/master/discovery.go index 9ea6ea78f97..1b024e6593a 100644 --- a/cmd/kubeadm/app/master/discovery.go +++ b/cmd/kubeadm/app/master/discovery.go @@ -24,6 +24,7 @@ import ( kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1" extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" @@ -43,18 +44,18 @@ const ( kubeDiscoverySecretName = "clusterinfo" ) -func encodeKubeDiscoverySecretData(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate) map[string][]byte { +func encodeKubeDiscoverySecretData(dcfg *kubeadmapi.TokenDiscovery, apicfg kubeadmapi.API, caCert *x509.Certificate) map[string][]byte { var ( data = map[string][]byte{} endpointList = []string{} tokenMap = map[string]string{} ) - for _, addr := range cfg.API.AdvertiseAddresses { - endpointList = append(endpointList, fmt.Sprintf("https://%s:%d", addr, cfg.API.BindPort)) + for _, addr := range apicfg.AdvertiseAddresses { + endpointList = append(endpointList, fmt.Sprintf("https://%s:%d", addr, apicfg.Port)) } - tokenMap[cfg.Secrets.TokenID] = cfg.Secrets.BearerToken + tokenMap[dcfg.ID] = dcfg.Secret data["endpoint-list.json"], _ = json.Marshal(endpointList) data["token-map.json"], _ = json.Marshal(tokenMap) @@ -83,7 +84,7 @@ func newKubeDiscoveryPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec { Ports: []v1.ContainerPort{ // TODO when CNI issue (#31307) is resolved, we should consider adding // `HostIP: s.API.AdvertiseAddrs[0]`, if there is only one address` - {Name: "http", ContainerPort: kubeadmapiext.DefaultDiscoveryBindPort, HostPort: cfg.Discovery.BindPort}, + {Name: "http", ContainerPort: kubeadmapiext.DefaultDiscoveryBindPort, HostPort: kubeadmutil.DiscoveryPort(cfg.Discovery.Token)}, }, SecurityContext: &v1.SecurityContext{ SELinuxOptions: &v1.SELinuxOptions{ @@ -110,7 +111,7 @@ func newKubeDiscovery(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certific Secret: &v1.Secret{ ObjectMeta: v1.ObjectMeta{Name: kubeDiscoverySecretName}, Type: v1.SecretTypeOpaque, - Data: encodeKubeDiscoverySecretData(cfg, caCert), + Data: encodeKubeDiscoverySecretData(cfg.Discovery.Token, cfg.API, caCert), }, } diff --git a/cmd/kubeadm/app/master/discovery_test.go b/cmd/kubeadm/app/master/discovery_test.go index 060c472067e..1f6c16bbc12 100644 --- a/cmd/kubeadm/app/master/discovery_test.go +++ b/cmd/kubeadm/app/master/discovery_test.go @@ -23,62 +23,6 @@ import ( kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) -func TestEncodeKubeDiscoverySecretData(t *testing.T) { - var tests = []struct { - cfg *kubeadmapi.MasterConfiguration - expected bool - }{ - { - cfg: &kubeadmapi.MasterConfiguration{ - API: kubeadmapi.API{BindPort: 123, AdvertiseAddresses: []string{"10.0.0.1"}}, - Networking: kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/1"}, - }, - expected: true, - }, - } - - for _, rt := range tests { - caCert := &x509.Certificate{} - actual := encodeKubeDiscoverySecretData(rt.cfg, caCert) - if (actual != nil) != rt.expected { - t.Errorf( - "failed encodeKubeDiscoverySecretData, return map[string][]byte was nil", - ) - } - } -} - -func TestNewKubeDiscoveryPodSpec(t *testing.T) { - var tests = []struct { - cfg *kubeadmapi.MasterConfiguration - p int32 - expected bool - }{ - { - cfg: &kubeadmapi.MasterConfiguration{ - Discovery: kubeadmapi.Discovery{BindPort: 123}, - }, - p: 123, - }, - { - cfg: &kubeadmapi.MasterConfiguration{ - Discovery: kubeadmapi.Discovery{BindPort: 456}, - }, - p: 456, - }, - } - for _, rt := range tests { - actual := newKubeDiscoveryPodSpec(rt.cfg) - if actual.Containers[0].Ports[0].HostPort != rt.p { - t.Errorf( - "failed newKubeDiscoveryPodSpec:\n\texpected: %d\n\t actual: %d", - rt.p, - actual.Containers[0].Ports[0].HostPort, - ) - } - } -} - func TestNewKubeDiscovery(t *testing.T) { var tests = []struct { cfg *kubeadmapi.MasterConfiguration @@ -87,8 +31,9 @@ func TestNewKubeDiscovery(t *testing.T) { }{ { cfg: &kubeadmapi.MasterConfiguration{ - API: kubeadmapi.API{BindPort: 123, AdvertiseAddresses: []string{"10.0.0.1"}}, + API: kubeadmapi.API{Port: 123, AdvertiseAddresses: []string{"10.0.0.1"}}, Networking: kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/1"}, + Discovery: kubeadmapi.Discovery{Token: &kubeadmapi.TokenDiscovery{}}, }, caCert: &x509.Certificate{}, }, diff --git a/cmd/kubeadm/app/master/kubeconfig.go b/cmd/kubeadm/app/master/kubeconfig.go index e750f6aa12f..811e0dff2e5 100644 --- a/cmd/kubeadm/app/master/kubeconfig.go +++ b/cmd/kubeadm/app/master/kubeconfig.go @@ -34,7 +34,7 @@ func CreateCertsAndConfigForClients(cfg kubeadmapi.API, clientNames []string, ca // TODO this is not great, but there is only one address we can use here // so we'll pick the first one, there is much of chance to have an empty // slice by the time this gets called - fmt.Sprintf("https://%s:%d", cfg.AdvertiseAddresses[0], cfg.BindPort), + fmt.Sprintf("https://%s:%d", cfg.AdvertiseAddresses[0], cfg.Port), certutil.EncodeCertPEM(caCert), ) diff --git a/cmd/kubeadm/app/master/manifests.go b/cmd/kubeadm/app/master/manifests.go index 1d9df68cc91..b54e2ee48b9 100644 --- a/cmd/kubeadm/app/master/manifests.go +++ b/cmd/kubeadm/app/master/manifests.go @@ -292,7 +292,7 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string { "--tls-cert-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/apiserver.pem", "--tls-private-key-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/apiserver-key.pem", "--token-auth-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/tokens.csv", - fmt.Sprintf("--secure-port=%d", cfg.API.BindPort), + fmt.Sprintf("--secure-port=%d", cfg.API.Port), "--allow-privileged", ) diff --git a/cmd/kubeadm/app/master/manifests_test.go b/cmd/kubeadm/app/master/manifests_test.go index d6d9e18f184..270ceb4fd01 100644 --- a/cmd/kubeadm/app/master/manifests_test.go +++ b/cmd/kubeadm/app/master/manifests_test.go @@ -364,7 +364,7 @@ func TestGetAPIServerCommand(t *testing.T) { }{ { cfg: &kubeadmapi.MasterConfiguration{ - API: kubeadm.API{BindPort: 123}, + API: kubeadm.API{Port: 123}, Networking: kubeadm.Networking{ServiceSubnet: "bar"}, }, expected: []string{ @@ -384,7 +384,7 @@ func TestGetAPIServerCommand(t *testing.T) { }, { cfg: &kubeadmapi.MasterConfiguration{ - API: kubeadm.API{BindPort: 123, AdvertiseAddresses: []string{"foo"}}, + API: kubeadm.API{Port: 123, AdvertiseAddresses: []string{"foo"}}, Networking: kubeadm.Networking{ServiceSubnet: "bar"}, }, expected: []string{ @@ -405,7 +405,7 @@ func TestGetAPIServerCommand(t *testing.T) { }, { cfg: &kubeadmapi.MasterConfiguration{ - API: kubeadm.API{BindPort: 123}, + API: kubeadm.API{Port: 123}, Networking: kubeadm.Networking{ServiceSubnet: "bar"}, Etcd: kubeadm.Etcd{CertFile: "fiz", KeyFile: "faz"}, }, @@ -429,7 +429,7 @@ func TestGetAPIServerCommand(t *testing.T) { // Make sure --kubelet-preferred-address-types { cfg: &kubeadmapi.MasterConfiguration{ - API: kubeadm.API{BindPort: 123, AdvertiseAddresses: []string{"foo"}}, + API: kubeadm.API{Port: 123, AdvertiseAddresses: []string{"foo"}}, Networking: kubeadm.Networking{ServiceSubnet: "bar"}, KubernetesVersion: "v1.5.3", }, diff --git a/cmd/kubeadm/app/master/tokens.go b/cmd/kubeadm/app/master/tokens.go index 994e081da4f..bf12b3a9e43 100644 --- a/cmd/kubeadm/app/master/tokens.go +++ b/cmd/kubeadm/app/master/tokens.go @@ -28,34 +28,32 @@ import ( "k8s.io/kubernetes/pkg/util/uuid" ) -func generateTokenIfNeeded(s *kubeadmapi.Secrets) error { - ok, err := kubeadmutil.UseGivenTokenIfValid(s) - // TODO(phase1+) @krousey: I know it won't happen with the way it is currently implemented, but this doesn't handle case where ok is true and err is non-nil. - if !ok { - if err != nil { - return err - } - err = kubeadmutil.GenerateToken(s) - if err != nil { - return err - } - fmt.Printf("[tokens] Generated token: %q\n", s.GivenToken) - } else { - fmt.Println("[tokens] Accepted provided token") +func generateTokenIfNeeded(d *kubeadmapi.TokenDiscovery) error { + ok, err := kubeadmutil.IsTokenValid(d) + if err != nil { + return err + } + if ok { + fmt.Println("[tokens] Accepted provided token") + return nil + } + if err := kubeadmutil.GenerateToken(d); err != nil { + fmt.Printf("[tokens] Generated token: %q\n", kubeadmutil.BearerToken(d)) + return nil + } else { + return err } - - return nil } -func CreateTokenAuthFile(s *kubeadmapi.Secrets) error { +func CreateTokenAuthFile(d *kubeadmapi.TokenDiscovery) error { tokenAuthFilePath := path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, "tokens.csv") - if err := generateTokenIfNeeded(s); err != nil { + if err := generateTokenIfNeeded(d); err != nil { return fmt.Errorf("failed to generate token(s) [%v]", err) } if err := os.MkdirAll(kubeadmapi.GlobalEnvParams.HostPKIPath, 0700); err != nil { return fmt.Errorf("failed to create directory %q [%v]", kubeadmapi.GlobalEnvParams.HostPKIPath, err) } - serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", s.BearerToken, uuid.NewUUID())) + serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", kubeadmutil.BearerToken(d), uuid.NewUUID())) // DumpReaderToFile create a file with mode 0600 if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil { return fmt.Errorf("failed to save token auth file (%q) [%v]", tokenAuthFilePath, err) diff --git a/cmd/kubeadm/app/master/tokens_test.go b/cmd/kubeadm/app/master/tokens_test.go index 3a09b403a3a..448dac8dbb1 100644 --- a/cmd/kubeadm/app/master/tokens_test.go +++ b/cmd/kubeadm/app/master/tokens_test.go @@ -17,67 +17,44 @@ limitations under the License. package master import ( - "fmt" - "io/ioutil" - "os" "testing" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) -func TestGenerateTokenIfNeeded(t *testing.T) { - var tests = []struct { - s kubeadmapi.Secrets - expected bool - }{ - {kubeadmapi.Secrets{GivenToken: "noperiod"}, false}, // not 2-part '.' format - {kubeadmapi.Secrets{GivenToken: "abcd.a"}, false}, // len(tokenID) != 6 - {kubeadmapi.Secrets{GivenToken: "abcdef.a"}, true}, - {kubeadmapi.Secrets{GivenToken: ""}, true}, - } - - for _, rt := range tests { - actual := generateTokenIfNeeded(&rt.s) - if (actual == nil) != rt.expected { - t.Errorf( - "failed UseGivenTokenIfValid:\n\texpected: %t\n\t actual: %t\n\t token:%s", - rt.expected, - (actual == nil), - rt.s.GivenToken, - ) +func TestValidTokenPopulatesSecrets(t *testing.T) { + t.Run("provided", func(t *testing.T) { + expectedID := "123456" + expectedSecret := "0123456789abcdef" + s := &kubeadmapi.TokenDiscovery{ + ID: expectedID, + Secret: expectedSecret, } - } -} -func TestCreateTokenAuthFile(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "") - if err != nil { - t.Fatalf("Couldn't create tmpdir") - } - defer os.Remove(tmpdir) - - // set up tmp GlobalEnvParams values for testing - oldEnv := kubeadmapi.GlobalEnvParams - kubeadmapi.GlobalEnvParams.HostPKIPath = fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir) - defer func() { kubeadmapi.GlobalEnvParams = oldEnv }() - - var tests = []struct { - s kubeadmapi.Secrets - expected bool - }{ - {kubeadmapi.Secrets{GivenToken: "noperiod"}, false}, // not 2-part '.' format - {kubeadmapi.Secrets{GivenToken: "abcd.a"}, false}, // len(tokenID) != 6 - {kubeadmapi.Secrets{GivenToken: "abcdef.a"}, true}, - {kubeadmapi.Secrets{GivenToken: ""}, true}, - } - for _, rt := range tests { - actual := CreateTokenAuthFile(&rt.s) - if (actual == nil) != rt.expected { - t.Errorf( - "failed WriteKubeconfigIfNotExists with an error:\n\texpected: %t\n\t actual: %t", - rt.expected, - (actual == nil), - ) + err := generateTokenIfNeeded(s) + if err != nil { + t.Errorf("generateTokenIfNeeded gave an error for a valid token: %v", err) } - } + if s.ID != expectedID { + t.Errorf("generateTokenIfNeeded did not populate the TokenID correctly; expected [%s] but got [%s]", expectedID, s.ID) + } + if s.Secret != expectedSecret { + t.Errorf("generateTokenIfNeeded did not populate the Token correctly; expected %v but got %v", expectedSecret, s.Secret) + } + }) + + t.Run("not provided", func(t *testing.T) { + s := &kubeadmapi.TokenDiscovery{} + + err := generateTokenIfNeeded(s) + if err != nil { + t.Errorf("generateTokenIfNeeded gave an error for a valid token: %v", err) + } + if s.ID != "" { + t.Errorf("generateTokenIfNeeded did not populate the TokenID correctly; expected ID to be non-empty") + } + if s.Secret != "" { + t.Errorf("generateTokenIfNeeded did not populate the Token correctly; expected Secret to be non-empty") + } + }) } diff --git a/cmd/kubeadm/app/node/bootstrap.go b/cmd/kubeadm/app/node/bootstrap.go index 00b1d55d498..9c586ea26bb 100644 --- a/cmd/kubeadm/app/node/bootstrap.go +++ b/cmd/kubeadm/app/node/bootstrap.go @@ -50,7 +50,7 @@ const retryTimeout = 5 // The function builds a client for every endpoint and concurrently keeps trying to connect to any one // of the provided endpoints. Blocks until at least one connection is established, then it stops the // connection attempts for other endpoints. -func EstablishMasterConnection(s *kubeadmapi.NodeConfiguration, clusterInfo *kubeadmapi.ClusterInfo) (*ConnectionDetails, error) { +func EstablishMasterConnection(c *kubeadmapi.TokenDiscovery, clusterInfo *kubeadmapi.ClusterInfo) (*ConnectionDetails, error) { hostName, err := os.Hostname() if err != nil { return nil, fmt.Errorf("failed to get node hostname [%v]", err) @@ -65,7 +65,7 @@ func EstablishMasterConnection(s *kubeadmapi.NodeConfiguration, clusterInfo *kub result := make(chan *ConnectionDetails) var wg sync.WaitGroup for _, endpoint := range endpoints { - clientSet, err := createClients(caCert, endpoint, s.Secrets.BearerToken, nodeName) + clientSet, err := createClients(caCert, endpoint, kubeadmutil.BearerToken(c), nodeName) if err != nil { fmt.Printf("[bootstrap] Warning: %s. Skipping endpoint %s\n", err, endpoint) continue diff --git a/cmd/kubeadm/app/node/bootstrap_test.go b/cmd/kubeadm/app/node/bootstrap_test.go index 949300aeb75..676dcefa60a 100644 --- a/cmd/kubeadm/app/node/bootstrap_test.go +++ b/cmd/kubeadm/app/node/bootstrap_test.go @@ -107,7 +107,7 @@ func TestEstablishMasterConnection(t *testing.T) { }, } for _, rt := range tests { - s := &kubeadmapi.NodeConfiguration{} + s := &kubeadmapi.TokenDiscovery{} c := &kubeadmapi.ClusterInfo{Endpoints: []string{rt.e}, CertificateAuthorities: []string{rt.c}} _, actual := EstablishMasterConnection(s, c) if (actual == nil) != rt.expect { diff --git a/cmd/kubeadm/app/node/csr.go b/cmd/kubeadm/app/node/csr.go index 62dfd305881..d144814cb09 100644 --- a/cmd/kubeadm/app/node/csr.go +++ b/cmd/kubeadm/app/node/csr.go @@ -18,16 +18,18 @@ package node import ( "fmt" + "os" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" + "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" "k8s.io/kubernetes/pkg/kubelet/util/csr" + "k8s.io/kubernetes/pkg/types" certutil "k8s.io/kubernetes/pkg/util/cert" ) -// PerformTLSBootstrap executes a certificate signing request with the -// provided connection details. -func PerformTLSBootstrap(connection *ConnectionDetails) (*clientcmdapi.Config, error) { +func PerformTLSBootstrapDeprecated(connection *ConnectionDetails) (*clientcmdapi.Config, error) { csrClient := connection.CertClient.CertificateSigningRequests() fmt.Println("[csr] Created API client to obtain unique certificate for this node, generating keys and certificate signing request") @@ -55,3 +57,49 @@ func PerformTLSBootstrap(connection *ConnectionDetails) (*clientcmdapi.Config, e return finalConfig, nil } + +// PerformTLSBootstrap executes a certificate signing request with the +// provided connection details. +func PerformTLSBootstrap(cfg *clientcmdapi.Config) error { + hostName, err := os.Hostname() + if err != nil { + return err + } + name := types.NodeName(hostName) + + rc, err := clientcmd.NewDefaultClientConfig(*cfg, nil).ClientConfig() + if err != nil { + return err + } + c, err := clientset.NewForConfig(rc) + if err != nil { + return err + } + fmt.Println(" created API client to obtain unique certificate for this node, generating keys and certificate signing request") + + key, err := certutil.MakeEllipticPrivateKeyPEM() + if err != nil { + return fmt.Errorf(" failed to generating private key [%v]", err) + } + cert, err := csr.RequestNodeCertificate(c.Certificates().CertificateSigningRequests(), key, name) + if err != nil { + return fmt.Errorf(" failed to request signed certificate from the API server [%v]", err) + } + fmtCert, err := certutil.FormatBytesCert(cert) + if err != nil { + return fmt.Errorf(" failed to format certificate [%v]", err) + } + fmt.Printf(" received signed certificate from the API server:\n%s\n", fmtCert) + fmt.Println(" generating kubelet configuration") + + cfg.AuthInfos["kubelet"] = &clientcmdapi.AuthInfo{ + ClientKeyData: key, + ClientCertificateData: []byte(fmtCert), + } + cfg.Contexts["kubelet"] = &clientcmdapi.Context{ + AuthInfo: "kubelet", + Cluster: cfg.Contexts[cfg.CurrentContext].Cluster, + } + cfg.CurrentContext = "kubelet" + return nil +} diff --git a/cmd/kubeadm/app/node/csr_test.go b/cmd/kubeadm/app/node/csr_test.go index 290f505f5f5..b04c6fe4613 100644 --- a/cmd/kubeadm/app/node/csr_test.go +++ b/cmd/kubeadm/app/node/csr_test.go @@ -67,7 +67,7 @@ func TestPerformTLSBootstrap(t *testing.T) { t.Fatalf("encountered an error while trying to get New Cert Client: %v", err) } cd.CertClient = tmpConfig - _, actual := PerformTLSBootstrap(cd) + _, actual := PerformTLSBootstrapDeprecated(cd) if (actual == nil) != rt.expect { t.Errorf( "failed createClients:\n\texpected: %t\n\t actual: %t", diff --git a/cmd/kubeadm/app/node/discovery.go b/cmd/kubeadm/app/node/discovery.go index aad37f7290b..38b0cb29cc1 100644 --- a/cmd/kubeadm/app/node/discovery.go +++ b/cmd/kubeadm/app/node/discovery.go @@ -32,9 +32,8 @@ import ( // the amount of time to wait between each request to the discovery API const discoveryRetryTimeout = 5 * time.Second -func RetrieveTrustedClusterInfo(s *kubeadmapi.NodeConfiguration) (*kubeadmapi.ClusterInfo, error) { - host, port := s.MasterAddresses[0], s.DiscoveryPort - requestURL := fmt.Sprintf("http://%s:%d/cluster-info/v1/?token-id=%s", host, port, s.Secrets.TokenID) +func RetrieveTrustedClusterInfo(d *kubeadmapi.TokenDiscovery) (*kubeadmapi.ClusterInfo, error) { + requestURL := fmt.Sprintf("http://%s/cluster-info/v1/?token-id=%s", d.Addresses[0], d.ID) req, err := http.NewRequest("GET", requestURL, nil) if err != nil { return nil, fmt.Errorf("failed to consturct an HTTP request [%v]", err) @@ -63,7 +62,7 @@ func RetrieveTrustedClusterInfo(s *kubeadmapi.NodeConfiguration) (*kubeadmapi.Cl fmt.Println("[discovery] Cluster info object received, verifying signature using given token") - output, err := object.Verify(s.Secrets.Token) + output, err := object.Verify([]byte(d.Secret)) if err != nil { return nil, fmt.Errorf("failed to verify JWS signature of received cluster info object [%v]", err) } diff --git a/cmd/kubeadm/app/node/discovery_test.go b/cmd/kubeadm/app/node/discovery_test.go index 4626b6c7124..c5efa5d8204 100644 --- a/cmd/kubeadm/app/node/discovery_test.go +++ b/cmd/kubeadm/app/node/discovery_test.go @@ -67,26 +67,26 @@ func TestRetrieveTrustedClusterInfo(t *testing.T) { } tests := []struct { h string - p int32 + p int payload string expect bool }{ { h: host, - p: int32(iPort), + p: iPort, payload: "", expect: false, }, { h: host, - p: int32(iPort), + p: iPort, payload: "foo", expect: false, }, } for _, rt := range tests { j.Payload = rt.payload - nc := &kubeadmapi.NodeConfiguration{MasterAddresses: []string{host}, DiscoveryPort: int32(iPort)} + nc := &kubeadmapi.TokenDiscovery{Addresses: []string{rt.h + ":" + strconv.Itoa(rt.p)}} _, actual := RetrieveTrustedClusterInfo(nc) if (actual == nil) != rt.expect { t.Errorf( diff --git a/cmd/kubeadm/app/preflight/checks.go b/cmd/kubeadm/app/preflight/checks.go index 432cba29399..d69642af39e 100644 --- a/cmd/kubeadm/app/preflight/checks.go +++ b/cmd/kubeadm/app/preflight/checks.go @@ -280,14 +280,13 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error { HostnameCheck{}, ServiceCheck{Service: "kubelet", CheckIfActive: false}, ServiceCheck{Service: "docker", CheckIfActive: true}, - FirewalldCheck{ports: []int{int(cfg.API.BindPort), int(cfg.Discovery.BindPort), 10250}}, - PortOpenCheck{port: int(cfg.API.BindPort)}, + FirewalldCheck{ports: []int{int(cfg.API.Port), 10250}}, + PortOpenCheck{port: int(cfg.API.Port)}, PortOpenCheck{port: 8080}, - PortOpenCheck{port: int(cfg.Discovery.BindPort)}, PortOpenCheck{port: 10250}, PortOpenCheck{port: 10251}, PortOpenCheck{port: 10252}, - HTTPProxyCheck{Proto: "https", Host: cfg.API.AdvertiseAddresses[0], Port: int(cfg.API.BindPort)}, + HTTPProxyCheck{Proto: "https", Host: cfg.API.AdvertiseAddresses[0], Port: int(cfg.API.Port)}, DirAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")}, DirAvailableCheck{Path: kubeadmapi.GlobalEnvParams.HostPKIPath}, DirAvailableCheck{Path: "/var/lib/kubelet"}, @@ -323,8 +322,6 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error { ServiceCheck{Service: "kubelet", CheckIfActive: false}, ServiceCheck{Service: "docker", CheckIfActive: true}, PortOpenCheck{port: 10250}, - HTTPProxyCheck{Proto: "https", Host: cfg.MasterAddresses[0], Port: int(cfg.APIPort)}, - HTTPProxyCheck{Proto: "http", Host: cfg.MasterAddresses[0], Port: int(cfg.DiscoveryPort)}, DirAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")}, DirAvailableCheck{Path: "/var/lib/kubelet"}, FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "kubelet.conf")}, diff --git a/cmd/kubeadm/app/util/BUILD b/cmd/kubeadm/app/util/BUILD index 2f90923a664..44fd55ede2e 100644 --- a/cmd/kubeadm/app/util/BUILD +++ b/cmd/kubeadm/app/util/BUILD @@ -19,6 +19,7 @@ go_library( tags = ["automanaged"], deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", "//pkg/client/unversioned/clientcmd:go_default_library", "//pkg/client/unversioned/clientcmd/api:go_default_library", diff --git a/cmd/kubeadm/app/util/tokens.go b/cmd/kubeadm/app/util/tokens.go index 2642802881a..e236db8817c 100644 --- a/cmd/kubeadm/app/util/tokens.go +++ b/cmd/kubeadm/app/util/tokens.go @@ -20,65 +20,76 @@ import ( "crypto/rand" "encoding/hex" "fmt" + "regexp" + "strconv" "strings" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" ) const ( - TokenIDLen = 6 - TokenBytes = 8 + TokenIDBytes = 3 + TokenBytes = 8 ) -func RandBytes(length int) ([]byte, string, error) { +func RandBytes(length int) (string, error) { b := make([]byte, length) _, err := rand.Read(b) if err != nil { - return nil, "", err + return "", err } - // It's only the tokenID that doesn't care about raw byte slice, - // so we just encoded it in place and ignore bytes slice where we - // do not want it - return b, hex.EncodeToString(b), nil + return hex.EncodeToString(b), nil } -func GenerateToken(s *kubeadmapi.Secrets) error { - _, tokenID, err := RandBytes(TokenIDLen / 2) +func GenerateToken(d *kubeadmapi.TokenDiscovery) error { + tokenID, err := RandBytes(TokenIDBytes) if err != nil { return err } - tokenBytes, token, err := RandBytes(TokenBytes) + token, err := RandBytes(TokenBytes) if err != nil { return err } - s.TokenID = tokenID - s.BearerToken = token - s.Token = tokenBytes - s.GivenToken = fmt.Sprintf("%s.%s", tokenID, token) + d.ID = tokenID + d.Secret = token return nil } -func UseGivenTokenIfValid(s *kubeadmapi.Secrets) (bool, error) { - if s.GivenToken == "" { - return false, nil // not given +var ( + tokenRegexpString = "^([a-zA-Z0-9]{6})\\.([a-zA-Z0-9]{16})$" + tokenRegexp = regexp.MustCompile(tokenRegexpString) +) + +func ParseToken(s string) (string, string, error) { + split := tokenRegexp.FindStringSubmatch(s) + if len(split) != 3 { + return "", "", fmt.Errorf("token %q was not of form %q", s, tokenRegexpString) } - fmt.Println("[tokens] Validating provided token") - givenToken := strings.Split(strings.ToLower(s.GivenToken), ".") - // TODO(phase1+) could also print more specific messages in each case - invalidErr := "[tokens] Provided token does not match expected <6 characters>.<16 characters> format - %s" - if len(givenToken) != 2 { - return false, fmt.Errorf(invalidErr, "not in 2-part dot-separated format") - } - if len(givenToken[0]) != TokenIDLen { - return false, fmt.Errorf(invalidErr, fmt.Sprintf( - "length of first part is incorrect [%d (given) != %d (expected) ]", - len(givenToken[0]), TokenIDLen)) - } - tokenBytes := []byte(givenToken[1]) - s.TokenID = givenToken[0] - s.BearerToken = givenToken[1] - s.Token = tokenBytes - return true, nil // given and valid + return split[1], split[2], nil + +} + +func BearerToken(d *kubeadmapi.TokenDiscovery) string { + return fmt.Sprintf("%s.%s", d.ID, d.Secret) +} + +func IsTokenValid(d *kubeadmapi.TokenDiscovery) (bool, error) { + return true, nil +} + +func DiscoveryPort(d *kubeadmapi.TokenDiscovery) int32 { + if len(d.Addresses) == 0 { + return kubeadmapiext.DefaultDiscoveryBindPort + } + split := strings.Split(d.Addresses[0], ":") + if len(split) == 1 { + return kubeadmapiext.DefaultDiscoveryBindPort + } + if i, err := strconv.Atoi(split[1]); err != nil { + return int32(i) + } + return kubeadmapiext.DefaultDiscoveryBindPort } diff --git a/cmd/kubeadm/app/util/tokens_test.go b/cmd/kubeadm/app/util/tokens_test.go index 288d132db3e..b3c8906fa08 100644 --- a/cmd/kubeadm/app/util/tokens_test.go +++ b/cmd/kubeadm/app/util/tokens_test.go @@ -17,185 +17,54 @@ limitations under the License. package util import ( - "bytes" - "strings" "testing" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) -func TestUsingEmptyTokenFails(t *testing.T) { - // Simulates what happens when you omit --token on the CLI - s := newSecretsWithToken("") - - given, err := UseGivenTokenIfValid(s) - if err != nil { - t.Errorf("UseGivenTokenIfValid returned an error when the token was omitted: %v", err) - } - if given { - t.Error("UseGivenTokenIfValid returned given = true when the token was omitted; expected false") - } -} - -func TestTokenValidationFailures(t *testing.T) { - var tests = []struct { - t string - expected bool - }{ - { - t: "1234567890123456789012", - expected: false, - }, - { - t: "12345.1234567890123456", - expected: false, - }, - { - t: ".1234567890123456", - expected: false, - }, - { - t: "123456.1234567890.123456", - expected: false, - }, +func TestTokenParseErrors(t *testing.T) { + invalidTokens := []string{ + "1234567890123456789012", + "12345.1234567890123456", + ".1234567890123456", + "123456.1234567890.123456", } - for _, rt := range tests { - s := newSecretsWithToken(rt.t) - _, err := UseGivenTokenIfValid(s) - if (err == nil) != rt.expected { - t.Errorf( - "failed UseGivenTokenIfValid and did not return an error for this invalid token: [%s]", - rt.t, - ) + for _, token := range invalidTokens { + if _, _, err := ParseToken(token); err == nil { + t.Errorf("generateTokenIfNeeded did not return an error for this invalid token: [%s]", token) } } } -func TestValidTokenPopulatesSecrets(t *testing.T) { - var tests = []struct { - token string - expectedToken []byte - expectedTokenID string - expectedBearerToken string - }{ - { - token: "123456.0123456789AbCdEf", - expectedToken: []byte("0123456789abcdef"), - expectedTokenID: "123456", - expectedBearerToken: "0123456789abcdef", - }, - } - - for _, rt := range tests { - s := newSecretsWithToken(rt.token) - - given, err := UseGivenTokenIfValid(s) - if err != nil { - t.Errorf("UseGivenTokenIfValid gave an error for a valid token: %v", err) - } - if !given { - t.Error("UseGivenTokenIfValid returned given = false when given a valid token") - } - if s.TokenID != rt.expectedTokenID { - t.Errorf("UseGivenTokenIfValid did not populate the TokenID correctly; expected [%s] but got [%s]", rt.expectedTokenID, s.TokenID) - } - if s.BearerToken != rt.expectedBearerToken { - t.Errorf("UseGivenTokenIfValid did not populate the BearerToken correctly; expected [%s] but got [%s]", rt.expectedBearerToken, s.BearerToken) - } - if !bytes.Equal(s.Token, rt.expectedToken) { - t.Errorf("UseGivenTokenIfValid did not populate the Token correctly; expected %v but got %v", rt.expectedToken, s.Token) - } - } -} - -func newSecretsWithToken(token string) *kubeadmapi.Secrets { - s := new(kubeadmapi.Secrets) - s.GivenToken = token - return s -} - func TestGenerateToken(t *testing.T) { - var genTest = []struct { - s kubeadmapi.Secrets - l int - n int - }{ - {kubeadmapi.Secrets{}, 2, 6}, - } + var cfg kubeadmapi.TokenDiscovery - for _, rt := range genTest { - GenerateToken(&rt.s) - givenToken := strings.Split(strings.ToLower(rt.s.GivenToken), ".") - if len(givenToken) != rt.l { - t.Errorf( - "failed GenerateToken num parts:\n\texpected: %d\n\t actual: %d", - rt.l, - len(givenToken), - ) - } - if len(givenToken[0]) != rt.n { - t.Errorf( - "failed GenerateToken first part length:\n\texpected: %d\n\t actual: %d", - rt.l, - len(givenToken), - ) - } + GenerateToken(&cfg) + if len(cfg.ID) != 6 { + t.Errorf("failed GenerateToken first part length:\n\texpected: 6\n\t actual: %d", len(cfg.ID)) } -} - -func TestUseGivenTokenIfValid(t *testing.T) { - var tokenTest = []struct { - s kubeadmapi.Secrets - expected bool - }{ - {kubeadmapi.Secrets{GivenToken: ""}, false}, // GivenToken == "" - {kubeadmapi.Secrets{GivenToken: "noperiod"}, false}, // not 2-part '.' format - {kubeadmapi.Secrets{GivenToken: "abcd.a"}, false}, // len(tokenID) != 6 - {kubeadmapi.Secrets{GivenToken: "abcdef.a"}, true}, - } - - for _, rt := range tokenTest { - actual, _ := UseGivenTokenIfValid(&rt.s) - if actual != rt.expected { - t.Errorf( - "failed UseGivenTokenIfValid:\n\texpected: %t\n\t actual: %t\n\t token:%s", - rt.expected, - actual, - rt.s.GivenToken, - ) - } + if len(cfg.Secret) != 16 { + t.Errorf("failed GenerateToken first part length:\n\texpected: 16\n\t actual: %d", len(cfg.Secret)) } } func TestRandBytes(t *testing.T) { - var randTest = []struct { - r int - l int - expected error - }{ - {0, 0, nil}, - {1, 1, nil}, - {2, 2, nil}, - {3, 3, nil}, - {100, 100, nil}, + var randTest = []int{ + 0, + 1, + 2, + 3, + 100, } for _, rt := range randTest { - actual, _, err := RandBytes(rt.r) - if err != rt.expected { - t.Errorf( - "failed RandBytes:\n\texpected: %s\n\t actual: %s", - rt.expected, - err, - ) + actual, err := RandBytes(rt) + if err != nil { + t.Errorf("failed RandBytes: %v", err) } - if len(actual) != rt.l { - t.Errorf( - "failed RandBytes:\n\texpected: %d\n\t actual: %d\n", - rt.l, - len(actual), - ) + if len(actual) != rt*2 { + t.Errorf("failed RandBytes:\n\texpected: %d\n\t actual: %d\n", rt*2, len(actual)) } } } diff --git a/cmd/kubeadm/test/token_test.go b/cmd/kubeadm/test/token_test.go index b9bda37d8e0..494cb4651d4 100644 --- a/cmd/kubeadm/test/token_test.go +++ b/cmd/kubeadm/test/token_test.go @@ -18,6 +18,8 @@ package kubeadm import ( "flag" + "os" + "path/filepath" "regexp" "testing" ) @@ -29,7 +31,7 @@ const ( var kubeadmPath string func init() { - flag.StringVar(&kubeadmPath, "kubeadm-path", "cluster/kubeadm.sh", "Location of kubeadm") + flag.StringVar(&kubeadmPath, "kubeadm-path", filepath.Join(os.Getenv("KUBE_ROOT"), "cluster/kubeadm.sh"), "Location of kubeadm") } func TestCmdTokenGenerate(t *testing.T) { diff --git a/pkg/api/testing/fuzzer.go b/pkg/api/testing/fuzzer.go index f9024d47076..2c0cd521333 100644 --- a/pkg/api/testing/fuzzer.go +++ b/pkg/api/testing/fuzzer.go @@ -544,16 +544,10 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz func(obj *kubeadm.MasterConfiguration, c fuzz.Continue) { c.FuzzNoCustom(obj) obj.KubernetesVersion = "v10" - obj.API.BindPort = 20 - obj.Discovery.BindPort = 20 + obj.API.Port = 20 obj.Networking.ServiceSubnet = "foo" obj.Networking.DNSDomain = "foo" }, - func(obj *kubeadm.NodeConfiguration, c fuzz.Continue) { - c.FuzzNoCustom(obj) - obj.APIPort = 20 - obj.DiscoveryPort = 20 - }, func(s *policy.PodDisruptionBudgetStatus, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again s.PodDisruptionsAllowed = int32(c.Rand.Intn(2))