@@ -28,6 +28,7 @@ import (
28
28
flag "github.com/spf13/pflag"
29
29
"k8s.io/apimachinery/pkg/util/sets"
30
30
clientset "k8s.io/client-go/kubernetes"
31
+ clientcmd "k8s.io/client-go/tools/clientcmd"
31
32
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
32
33
"k8s.io/klog"
33
34
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@@ -308,44 +309,57 @@ func newJoinOptions() *joinOptions {
308
309
// newJoinData returns a new joinData struct to be used for the execution of the kubeadm join workflow.
309
310
// This func takes care of validating joinOptions passed to the command, and then it converts
310
311
// options into the internal JoinConfiguration type that is used as input all the phases in the kubeadm join workflow
311
- func newJoinData (cmd * cobra.Command , args []string , options * joinOptions , out io.Writer ) (* joinData , error ) {
312
+ func newJoinData (cmd * cobra.Command , args []string , opt * joinOptions , out io.Writer ) (* joinData , error ) {
312
313
// Re-apply defaults to the public kubeadm API (this will set only values not exposed/not set as a flags)
313
- kubeadmscheme .Scheme .Default (options .externalcfg )
314
+ kubeadmscheme .Scheme .Default (opt .externalcfg )
314
315
315
316
// Validate standalone flags values and/or combination of flags and then assigns
316
317
// validated values to the public kubeadm config API when applicable
317
318
318
319
// if a token is provided, use this value for both discovery-token and tls-bootstrap-token when those values are not provided
319
- if len (options .token ) > 0 {
320
- if len (options .externalcfg .Discovery .TLSBootstrapToken ) == 0 {
321
- options .externalcfg .Discovery .TLSBootstrapToken = options .token
320
+ if len (opt .token ) > 0 {
321
+ if len (opt .externalcfg .Discovery .TLSBootstrapToken ) == 0 {
322
+ opt .externalcfg .Discovery .TLSBootstrapToken = opt .token
322
323
}
323
- if len (options .externalcfg .Discovery .BootstrapToken .Token ) == 0 {
324
- options .externalcfg .Discovery .BootstrapToken .Token = options .token
324
+ if len (opt .externalcfg .Discovery .BootstrapToken .Token ) == 0 {
325
+ opt .externalcfg .Discovery .BootstrapToken .Token = opt .token
325
326
}
326
327
}
327
328
328
329
// if a file or URL from which to load cluster information was not provided, unset the Discovery.File object
329
- if len (options .externalcfg .Discovery .File .KubeConfigPath ) == 0 {
330
- options .externalcfg .Discovery .File = nil
330
+ if len (opt .externalcfg .Discovery .File .KubeConfigPath ) == 0 {
331
+ opt .externalcfg .Discovery .File = nil
331
332
}
332
333
333
334
// if an APIServerEndpoint from which to retrive cluster information was not provided, unset the Discovery.BootstrapToken object
334
335
if len (args ) == 0 {
335
- options .externalcfg .Discovery .BootstrapToken = nil
336
+ opt .externalcfg .Discovery .BootstrapToken = nil
336
337
} else {
337
- if len (options .cfgPath ) == 0 && len (args ) > 1 {
338
+ if len (opt .cfgPath ) == 0 && len (args ) > 1 {
338
339
klog .Warningf ("[join] WARNING: More than one API server endpoint supplied on command line %v. Using the first one." , args )
339
340
}
340
- options .externalcfg .Discovery .BootstrapToken .APIServerEndpoint = args [0 ]
341
+ opt .externalcfg .Discovery .BootstrapToken .APIServerEndpoint = args [0 ]
341
342
}
342
343
343
344
// if not joining a control plane, unset the ControlPlane object
344
- if ! options .controlPlane {
345
- options .externalcfg .ControlPlane = nil
345
+ if ! opt .controlPlane {
346
+ opt .externalcfg .ControlPlane = nil
346
347
}
347
348
348
- ignorePreflightErrorsSet , err := validation .ValidateIgnorePreflightErrors (options .ignorePreflightErrors )
349
+ // if the admin.conf file already exists, use it for skipping the discovery process.
350
+ // NB. this case can happen when we are joining a control-plane node only (and phases are invoked atomically)
351
+ var adminKubeConfigPath = kubeadmconstants .GetAdminKubeConfigPath ()
352
+ var tlsBootstrapCfg * clientcmdapi.Config
353
+ if _ , err := os .Stat (adminKubeConfigPath ); err == nil && opt .controlPlane {
354
+ // use the admin.conf as tlsBootstrapCfg, that is the kubeconfig file used for reading the kubeadm-config during discovery
355
+ klog .V (1 ).Infof ("[join] found %s. Use it for skipping discovery" , adminKubeConfigPath )
356
+ tlsBootstrapCfg , err = clientcmd .LoadFromFile (adminKubeConfigPath )
357
+ if err != nil {
358
+ return nil , errors .Wrapf (err , "Error loading %s" , adminKubeConfigPath )
359
+ }
360
+ }
361
+
362
+ ignorePreflightErrorsSet , err := validation .ValidateIgnorePreflightErrors (opt .ignorePreflightErrors )
349
363
if err != nil {
350
364
return nil , err
351
365
}
@@ -356,25 +370,35 @@ func newJoinData(cmd *cobra.Command, args []string, options *joinOptions, out io
356
370
357
371
// Either use the config file if specified, or convert public kubeadm API to the internal JoinConfiguration
358
372
// and validates JoinConfiguration
359
- if options .externalcfg .NodeRegistration .Name == "" {
373
+ if opt .externalcfg .NodeRegistration .Name == "" {
360
374
klog .V (1 ).Infoln ("[join] found NodeName empty; using OS hostname as NodeName" )
361
375
}
362
376
363
- if options .externalcfg .ControlPlane != nil && options .externalcfg .ControlPlane .LocalAPIEndpoint .AdvertiseAddress == "" {
377
+ if opt .externalcfg .ControlPlane != nil && opt .externalcfg .ControlPlane .LocalAPIEndpoint .AdvertiseAddress == "" {
364
378
klog .V (1 ).Infoln ("[join] found advertiseAddress empty; using default interface's IP address as advertiseAddress" )
365
379
}
366
380
367
- cfg , err := configutil .LoadOrDefaultJoinConfiguration (options .cfgPath , options .externalcfg )
381
+ // in case the command doesn't have flags for discovery, makes the join cfg validation pass checks on discovery
382
+ if cmd .Flags ().Lookup (options .FileDiscovery ) == nil {
383
+ if _ , err := os .Stat (adminKubeConfigPath ); os .IsNotExist (err ) {
384
+ return nil , errors .Errorf ("File %s does not exists. Please use 'kubeadm join phase control-plane-prepare' subcommands to generate it." , adminKubeConfigPath )
385
+ }
386
+ klog .V (1 ).Infof ("[join] found discovery flags missing for this command. using FileDiscovery: %s" , adminKubeConfigPath )
387
+ opt .externalcfg .Discovery .File = & kubeadmapiv1beta1.FileDiscovery {KubeConfigPath : adminKubeConfigPath }
388
+ opt .externalcfg .Discovery .BootstrapToken = nil //NB. this could be removed when we get better control on args (e.g. phases without discovery should have NoArgs )
389
+ }
390
+
391
+ cfg , err := configutil .LoadOrDefaultJoinConfiguration (opt .cfgPath , opt .externalcfg )
368
392
if err != nil {
369
393
return nil , err
370
394
}
371
395
372
- // override node name and CRI socket from the command line options
373
- if options .externalcfg .NodeRegistration .Name != "" {
374
- cfg .NodeRegistration .Name = options .externalcfg .NodeRegistration .Name
396
+ // override node name and CRI socket from the command line opt
397
+ if opt .externalcfg .NodeRegistration .Name != "" {
398
+ cfg .NodeRegistration .Name = opt .externalcfg .NodeRegistration .Name
375
399
}
376
- if options .externalcfg .NodeRegistration .CRISocket != "" {
377
- cfg .NodeRegistration .CRISocket = options .externalcfg .NodeRegistration .CRISocket
400
+ if opt .externalcfg .NodeRegistration .CRISocket != "" {
401
+ cfg .NodeRegistration .CRISocket = opt .externalcfg .NodeRegistration .CRISocket
378
402
}
379
403
380
404
if cfg .ControlPlane != nil {
@@ -385,9 +409,10 @@ func newJoinData(cmd *cobra.Command, args []string, options *joinOptions, out io
385
409
386
410
return & joinData {
387
411
cfg : cfg ,
412
+ tlsBootstrapCfg : tlsBootstrapCfg ,
388
413
ignorePreflightErrors : ignorePreflightErrorsSet ,
389
414
outputWriter : out ,
390
- certificateKey : options .certificateKey ,
415
+ certificateKey : opt .certificateKey ,
391
416
}, nil
392
417
}
393
418
0 commit comments