@@ -20,6 +20,7 @@ import (
20
20
"fmt"
21
21
"io"
22
22
"os"
23
+ "strings"
23
24
"text/template"
24
25
25
26
"github.com/lithammer/dedent"
@@ -127,6 +128,7 @@ type joinOptions struct {
127
128
controlPlane bool
128
129
ignorePreflightErrors []string
129
130
externalcfg * kubeadmapiv1beta2.JoinConfiguration
131
+ joinControlPlane * kubeadmapiv1beta2.JoinControlPlane
130
132
kustomizeDir string
131
133
}
132
134
@@ -199,7 +201,7 @@ func NewCmdJoin(out io.Writer, joinOptions *joinOptions) *cobra.Command {
199
201
Args : cobra .MaximumNArgs (1 ),
200
202
}
201
203
202
- addJoinConfigFlags (cmd .Flags (), joinOptions .externalcfg )
204
+ addJoinConfigFlags (cmd .Flags (), joinOptions .externalcfg , joinOptions . joinControlPlane )
203
205
addJoinOtherFlags (cmd .Flags (), joinOptions )
204
206
205
207
joinRunner .AppendPhase (phases .NewPreflightPhase ())
@@ -211,7 +213,7 @@ func NewCmdJoin(out io.Writer, joinOptions *joinOptions) *cobra.Command {
211
213
// sets the data builder function, that will be used by the runner
212
214
// both when running the entire workflow or single phases
213
215
joinRunner .SetDataInitializer (func (cmd * cobra.Command , args []string ) (workflow.RunData , error ) {
214
- return newJoinData (cmd , args , joinOptions , out )
216
+ return newJoinData (cmd , args , joinOptions , out , kubeadmconstants . GetAdminKubeConfigPath () )
215
217
})
216
218
217
219
// binds the Runner to kubeadm join command by altering
@@ -222,22 +224,22 @@ func NewCmdJoin(out io.Writer, joinOptions *joinOptions) *cobra.Command {
222
224
}
223
225
224
226
// addJoinConfigFlags adds join flags bound to the config to the specified flagset
225
- func addJoinConfigFlags (flagSet * flag.FlagSet , cfg * kubeadmapiv1beta2.JoinConfiguration ) {
227
+ func addJoinConfigFlags (flagSet * flag.FlagSet , cfg * kubeadmapiv1beta2.JoinConfiguration , jcp * kubeadmapiv1beta2. JoinControlPlane ) {
226
228
flagSet .StringVar (
227
229
& cfg .NodeRegistration .Name , options .NodeName , cfg .NodeRegistration .Name ,
228
230
`Specify the node name.` ,
229
231
)
230
232
flagSet .StringVar (
231
- & cfg . ControlPlane . CertificateKey , options .CertificateKey , "" ,
233
+ & jcp . CertificateKey , options .CertificateKey , jcp . CertificateKey ,
232
234
"Use this key to decrypt the certificate secrets uploaded by init." ,
233
235
)
234
236
// add control plane endpoint flags to the specified flagset
235
237
flagSet .StringVar (
236
- & cfg . ControlPlane . LocalAPIEndpoint .AdvertiseAddress , options .APIServerAdvertiseAddress , cfg . ControlPlane .LocalAPIEndpoint .AdvertiseAddress ,
238
+ & jcp . LocalAPIEndpoint .AdvertiseAddress , options .APIServerAdvertiseAddress , jcp .LocalAPIEndpoint .AdvertiseAddress ,
237
239
"If the node should host a new control plane instance, the IP address the API Server will advertise it's listening on. If not set the default network interface will be used." ,
238
240
)
239
241
flagSet .Int32Var (
240
- & cfg . ControlPlane . LocalAPIEndpoint .BindPort , options .APIServerBindPort , cfg . ControlPlane .LocalAPIEndpoint .BindPort ,
242
+ & jcp . LocalAPIEndpoint .BindPort , options .APIServerBindPort , jcp .LocalAPIEndpoint .BindPort ,
241
243
"If the node should host a new control plane instance, the port for the API Server to bind to." ,
242
244
)
243
245
// adds bootstrap token specific discovery flags to the specified flagset
@@ -297,18 +299,29 @@ func newJoinOptions() *joinOptions {
297
299
externalcfg .Discovery .BootstrapToken = & kubeadmapiv1beta2.BootstrapTokenDiscovery {}
298
300
externalcfg .ControlPlane = & kubeadmapiv1beta2.JoinControlPlane {}
299
301
302
+ // This object is used for storage of control-plane flags.
303
+ joinControlPlane := & kubeadmapiv1beta2.JoinControlPlane {}
304
+
300
305
// Apply defaults
301
306
kubeadmscheme .Scheme .Default (externalcfg )
307
+ kubeadmapiv1beta2 .SetDefaults_JoinControlPlane (joinControlPlane )
302
308
303
309
return & joinOptions {
304
- externalcfg : externalcfg ,
310
+ externalcfg : externalcfg ,
311
+ joinControlPlane : joinControlPlane ,
305
312
}
306
313
}
307
314
308
315
// newJoinData returns a new joinData struct to be used for the execution of the kubeadm join workflow.
309
316
// This func takes care of validating joinOptions passed to the command, and then it converts
310
317
// 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 , opt * joinOptions , out io.Writer ) (* joinData , error ) {
318
+ func newJoinData (cmd * cobra.Command , args []string , opt * joinOptions , out io.Writer , adminKubeConfigPath string ) (* joinData , error ) {
319
+
320
+ // Validate the mixed arguments with --config and return early on errors
321
+ if err := validation .ValidateMixedArguments (cmd .Flags ()); err != nil {
322
+ return nil , err
323
+ }
324
+
312
325
// Re-apply defaults to the public kubeadm API (this will set only values not exposed/not set as a flags)
313
326
kubeadmscheme .Scheme .Default (opt .externalcfg )
314
327
@@ -340,17 +353,32 @@ func newJoinData(cmd *cobra.Command, args []string, opt *joinOptions, out io.Wri
340
353
opt .externalcfg .Discovery .BootstrapToken .APIServerEndpoint = args [0 ]
341
354
}
342
355
343
- // if not joining a control plane, unset the ControlPlane object
356
+ // Include the JoinControlPlane with user flags
357
+ opt .externalcfg .ControlPlane = opt .joinControlPlane
358
+
359
+ // If not passing --control-plane, unset the ControlPlane object
344
360
if ! opt .controlPlane {
345
- if opt .externalcfg .ControlPlane != nil {
346
- klog .Warningf ("[preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when %s flag is not set." , options .ControlPlane )
361
+ // Use a defaulted JoinControlPlane object to detect if the user has passed
362
+ // other control-plane related flags.
363
+ defaultJCP := & kubeadmapiv1beta2.JoinControlPlane {}
364
+ kubeadmapiv1beta2 .SetDefaults_JoinControlPlane (defaultJCP )
365
+
366
+ // This list must match the JCP flags in addJoinConfigFlags()
367
+ joinControlPlaneFlags := []string {
368
+ options .CertificateKey ,
369
+ options .APIServerAdvertiseAddress ,
370
+ options .APIServerBindPort ,
371
+ }
372
+
373
+ if * opt .joinControlPlane != * defaultJCP {
374
+ klog .Warningf ("[preflight] WARNING: --%s is also required when passing control-plane " +
375
+ "related flags such as [%s]" , options .ControlPlane , strings .Join (joinControlPlaneFlags , ", " ))
347
376
}
348
377
opt .externalcfg .ControlPlane = nil
349
378
}
350
379
351
380
// if the admin.conf file already exists, use it for skipping the discovery process.
352
381
// NB. this case can happen when we are joining a control-plane node only (and phases are invoked atomically)
353
- var adminKubeConfigPath = kubeadmconstants .GetAdminKubeConfigPath ()
354
382
var tlsBootstrapCfg * clientcmdapi.Config
355
383
if _ , err := os .Stat (adminKubeConfigPath ); err == nil && opt .controlPlane {
356
384
// use the admin.conf as tlsBootstrapCfg, that is the kubeconfig file used for reading the kubeadm-config during discovery
@@ -361,10 +389,6 @@ func newJoinData(cmd *cobra.Command, args []string, opt *joinOptions, out io.Wri
361
389
}
362
390
}
363
391
364
- if err := validation .ValidateMixedArguments (cmd .Flags ()); err != nil {
365
- return nil , err
366
- }
367
-
368
392
// Either use the config file if specified, or convert public kubeadm API to the internal JoinConfiguration
369
393
// and validates JoinConfiguration
370
394
if opt .externalcfg .NodeRegistration .Name == "" {
0 commit comments